]> nv-tegra.nvidia Code Review - linux-2.6.git/commitdiff
Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Tue, 3 Jan 2012 20:16:34 +0000 (15:16 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Tue, 3 Jan 2012 20:16:34 +0000 (15:16 -0500)
Conflicts:
drivers/net/wireless/b43/dma.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c

18 files changed:
1  2 
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath9k/eeprom_def.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/b43/dma.c
drivers/net/wireless/b43/main.c
drivers/net/wireless/b43/phy_n.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/iwlwifi/iwl-trans-pcie.c
drivers/net/wireless/mwl8k.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/wifi.h
include/net/bluetooth/l2cap.h
net/bluetooth/hci_event.c
net/bluetooth/hci_sock.c
net/bluetooth/l2cap_core.c
net/bluetooth/rfcomm/core.c
net/bluetooth/sco.c

index 5acb4a4b93bf33b4870b9f2bd3055142ee3734b2,368ecbd172a3d03225d7d7ccfc6a19d21aee61f9..7f55be3092d1c63698bc2f9d83d88d6ce2769868
@@@ -33,6 -33,80 +33,80 @@@ module_param(debug_mask, uint, 0644)
  module_param(testmode, uint, 0644);
  module_param(suspend_cutpower, bool, 0444);
  
+ static const struct ath6kl_hw hw_list[] = {
+       {
+               .id                             = AR6003_HW_2_0_VERSION,
+               .name                           = "ar6003 hw 2.0",
+               .dataset_patch_addr             = 0x57e884,
+               .app_load_addr                  = 0x543180,
+               .board_ext_data_addr            = 0x57e500,
+               .reserved_ram_size              = 6912,
+               .refclk_hz                      = 26000000,
+               .uarttx_pin                     = 8,
+               /* hw2.0 needs override address hardcoded */
+               .app_start_override_addr        = 0x944C00,
+               .fw_otp                 = AR6003_HW_2_0_OTP_FILE,
+               .fw                     = AR6003_HW_2_0_FIRMWARE_FILE,
+               .fw_tcmd                = AR6003_HW_2_0_TCMD_FIRMWARE_FILE,
+               .fw_patch               = AR6003_HW_2_0_PATCH_FILE,
+               .fw_api2                = AR6003_HW_2_0_FIRMWARE_2_FILE,
+               .fw_board               = AR6003_HW_2_0_BOARD_DATA_FILE,
+               .fw_default_board       = AR6003_HW_2_0_DEFAULT_BOARD_DATA_FILE,
+       },
+       {
+               .id                             = AR6003_HW_2_1_1_VERSION,
+               .name                           = "ar6003 hw 2.1.1",
+               .dataset_patch_addr             = 0x57ff74,
+               .app_load_addr                  = 0x1234,
+               .board_ext_data_addr            = 0x542330,
+               .reserved_ram_size              = 512,
+               .refclk_hz                      = 26000000,
+               .uarttx_pin                     = 8,
+               .fw_otp                 = AR6003_HW_2_1_1_OTP_FILE,
+               .fw                     = AR6003_HW_2_1_1_FIRMWARE_FILE,
+               .fw_tcmd                = AR6003_HW_2_1_1_TCMD_FIRMWARE_FILE,
+               .fw_patch               = AR6003_HW_2_1_1_PATCH_FILE,
+               .fw_api2                = AR6003_HW_2_1_1_FIRMWARE_2_FILE,
+               .fw_board               = AR6003_HW_2_1_1_BOARD_DATA_FILE,
+               .fw_default_board       = AR6003_HW_2_1_1_DEFAULT_BOARD_DATA_FILE,
+       },
+       {
+               .id                             = AR6004_HW_1_0_VERSION,
+               .name                           = "ar6004 hw 1.0",
+               .dataset_patch_addr             = 0x57e884,
+               .app_load_addr                  = 0x1234,
+               .board_ext_data_addr            = 0x437000,
+               .reserved_ram_size              = 19456,
+               .board_addr                     = 0x433900,
+               .refclk_hz                      = 26000000,
+               .uarttx_pin                     = 11,
+               .fw                     = AR6004_HW_1_0_FIRMWARE_FILE,
+               .fw_api2                = AR6004_HW_1_0_FIRMWARE_2_FILE,
+               .fw_board               = AR6004_HW_1_0_BOARD_DATA_FILE,
+               .fw_default_board       = AR6004_HW_1_0_DEFAULT_BOARD_DATA_FILE,
+       },
+       {
+               .id                             = AR6004_HW_1_1_VERSION,
+               .name                           = "ar6004 hw 1.1",
+               .dataset_patch_addr             = 0x57e884,
+               .app_load_addr                  = 0x1234,
+               .board_ext_data_addr            = 0x437000,
+               .reserved_ram_size              = 11264,
+               .board_addr                     = 0x43d400,
+               .refclk_hz                      = 40000000,
+               .uarttx_pin                     = 11,
+               .fw                     = AR6004_HW_1_1_FIRMWARE_FILE,
+               .fw_api2                = AR6004_HW_1_1_FIRMWARE_2_FILE,
+               .fw_board               = AR6004_HW_1_1_BOARD_DATA_FILE,
+               .fw_default_board       = AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE,
+       },
+ };
  /*
   * Include definitions here that can be used to tune the WLAN module
   * behavior. Different customers can tune the behavior as per their needs,
   */
  #define WLAN_CONFIG_DISCONNECT_TIMEOUT 10
  
- #define CONFIG_AR600x_DEBUG_UART_TX_PIN 8
  
  #define ATH6KL_DATA_OFFSET    64
  struct sk_buff *ath6kl_buf_alloc(int size)
@@@ -348,11 -421,7 +421,7 @@@ static int ath6kl_target_config_wlan_pa
                        status = -EIO;
                }
  
-       /*
-        * FIXME: Make sure p2p configurations are not applied to
-        * non-p2p capable interfaces when multivif support is enabled.
-        */
-       if (ar->p2p) {
+       if (ar->p2p && (ar->vif_max == 1 || idx)) {
                ret = ath6kl_wmi_info_req_cmd(ar->wmi, idx,
                                              P2P_FLAG_CAPABILITIES_REQ |
                                              P2P_FLAG_MACADDR_REQ |
                        ath6kl_dbg(ATH6KL_DBG_TRC, "failed to request P2P "
                                   "capabilities (%d) - assuming P2P not "
                                   "supported\n", ret);
 -                      ar->p2p = 0;
 +                      ar->p2p = false;
                }
        }
  
-       /*
-        * FIXME: Make sure p2p configurations are not applied to
-        * non-p2p capable interfaces when multivif support is enabled.
-        */
-       if (ar->p2p) {
+       if (ar->p2p && (ar->vif_max == 1 || idx)) {
                /* Enable Probe Request reporting for P2P */
                ret = ath6kl_wmi_probe_report_req_cmd(ar->wmi, idx, true);
                if (ret) {
@@@ -385,7 -450,7 +450,7 @@@ int ath6kl_configure_target(struct ath6
  {
        u32 param, ram_reserved_size;
        u8 fw_iftype, fw_mode = 0, fw_submode = 0;
-       int i;
+       int i, status;
  
        /*
         * Note: Even though the firmware interface type is
         */
        fw_iftype = HI_OPTION_FW_MODE_BSS_STA;
  
-       for (i = 0; i < MAX_NUM_VIF; i++)
+       for (i = 0; i < ar->vif_max; i++)
                fw_mode |= fw_iftype << (i * HI_OPTION_FW_MODE_BITS);
  
        /*
                fw_submode |= HI_OPTION_FW_SUBMODE_NONE <<
                              (i * HI_OPTION_FW_SUBMODE_BITS);
  
-       for (i = ar->max_norm_iface; i < MAX_NUM_VIF; i++)
+       for (i = ar->max_norm_iface; i < ar->vif_max; i++)
                fw_submode |= HI_OPTION_FW_SUBMODE_P2PDEV <<
                              (i * HI_OPTION_FW_SUBMODE_BITS);
  
-       /*
-        * FIXME: This needs to be removed once the multivif
-        * support is enabled.
-        */
-       if (ar->p2p)
+       if (ar->p2p && ar->vif_max == 1)
                fw_submode = HI_OPTION_FW_SUBMODE_P2PDEV;
  
        param = HTC_PROTOCOL_VERSION;
                return -EIO;
        }
  
-       param |= (MAX_NUM_VIF << HI_OPTION_NUM_DEV_SHIFT);
+       param |= (ar->vif_max << HI_OPTION_NUM_DEV_SHIFT);
        param |= fw_mode << HI_OPTION_FW_MODE_SHIFT;
        param |= fw_submode << HI_OPTION_FW_SUBMODE_SHIFT;
  
                /* use default number of control buffers */
                return -EIO;
  
+       /* Configure GPIO AR600x UART */
+       param = ar->hw.uarttx_pin;
+       status = ath6kl_bmi_write(ar,
+                               ath6kl_get_hi_item_addr(ar,
+                               HI_ITEM(hi_dbg_uart_txpin)),
+                               (u8 *)&param, 4);
+       if (status)
+               return status;
+       /* Configure target refclk_hz */
+       param =  ar->hw.refclk_hz;
+       status = ath6kl_bmi_write(ar,
+                               ath6kl_get_hi_item_addr(ar,
+                               HI_ITEM(hi_refclk_hz)),
+                               (u8 *)&param, 4);
+       if (status)
+               return status;
        return 0;
  }
  
@@@ -550,11 -629,11 +629,11 @@@ static int ath6kl_get_fw(struct ath6kl 
  static const char *get_target_ver_dir(const struct ath6kl *ar)
  {
        switch (ar->version.target_ver) {
-       case AR6003_REV1_VERSION:
+       case AR6003_HW_1_0_VERSION:
                return "ath6k/AR6003/hw1.0";
-       case AR6003_REV2_VERSION:
+       case AR6003_HW_2_0_VERSION:
                return "ath6k/AR6003/hw2.0";
-       case AR6003_REV3_VERSION:
+       case AR6003_HW_2_1_1_VERSION:
                return "ath6k/AR6003/hw2.1.1";
        }
        ath6kl_warn("%s: unsupported target version 0x%x.\n", __func__,
@@@ -612,17 -691,10 +691,10 @@@ static int ath6kl_fetch_board_file(stru
        if (ar->fw_board != NULL)
                return 0;
  
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_BOARD_DATA_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               filename = AR6004_REV1_BOARD_DATA_FILE;
-               break;
-       default:
-               filename = AR6003_REV3_BOARD_DATA_FILE;
-               break;
-       }
+       if (WARN_ON(ar->hw.fw_board == NULL))
+               return -EINVAL;
+       filename = ar->hw.fw_board;
  
        ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
                            &ar->fw_board_len);
        ath6kl_warn("Failed to get board file %s (%d), trying to find default board file.\n",
                    filename, ret);
  
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_DEFAULT_BOARD_DATA_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               filename = AR6004_REV1_DEFAULT_BOARD_DATA_FILE;
-               break;
-       default:
-               filename = AR6003_REV3_DEFAULT_BOARD_DATA_FILE;
-               break;
-       }
+       filename = ar->hw.fw_default_board;
  
        ret = ath6kl_get_fw(ar, filename, &ar->fw_board,
                            &ar->fw_board_len);
@@@ -674,19 -736,14 +736,14 @@@ static int ath6kl_fetch_otp_file(struc
        if (ar->fw_otp != NULL)
                return 0;
  
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_OTP_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               ath6kl_dbg(ATH6KL_DBG_TRC, "AR6004 doesn't need OTP file\n");
+       if (ar->hw.fw_otp == NULL) {
+               ath6kl_dbg(ATH6KL_DBG_BOOT,
+                          "no OTP file configured for this hw\n");
                return 0;
-               break;
-       default:
-               filename = AR6003_REV3_OTP_FILE;
-               break;
        }
  
+       filename = ar->hw.fw_otp;
        ret = ath6kl_get_fw(ar, filename, &ar->fw_otp,
                            &ar->fw_otp_len);
        if (ret) {
@@@ -707,38 -764,22 +764,22 @@@ static int ath6kl_fetch_fw_file(struct 
                return 0;
  
        if (testmode) {
-               switch (ar->version.target_ver) {
-               case AR6003_REV2_VERSION:
-                       filename = AR6003_REV2_TCMD_FIRMWARE_FILE;
-                       break;
-               case AR6003_REV3_VERSION:
-                       filename = AR6003_REV3_TCMD_FIRMWARE_FILE;
-                       break;
-               case AR6004_REV1_VERSION:
-                       ath6kl_warn("testmode not supported with ar6004\n");
+               if (ar->hw.fw_tcmd == NULL) {
+                       ath6kl_warn("testmode not supported\n");
                        return -EOPNOTSUPP;
-               default:
-                       ath6kl_warn("unknown target version: 0x%x\n",
-                                      ar->version.target_ver);
-                       return -EINVAL;
                }
  
+               filename = ar->hw.fw_tcmd;
                set_bit(TESTMODE, &ar->flag);
  
                goto get_fw;
        }
  
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_FIRMWARE_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               filename = AR6004_REV1_FIRMWARE_FILE;
-               break;
-       default:
-               filename = AR6003_REV3_FIRMWARE_FILE;
-               break;
-       }
+       if (WARN_ON(ar->hw.fw == NULL))
+               return -EINVAL;
+       filename = ar->hw.fw;
  
  get_fw:
        ret = ath6kl_get_fw(ar, filename, &ar->fw, &ar->fw_len);
@@@ -756,27 -797,20 +797,20 @@@ static int ath6kl_fetch_patch_file(stru
        const char *filename;
        int ret;
  
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_PATCH_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               /* FIXME: implement for AR6004 */
+       if (ar->fw_patch != NULL)
                return 0;
-               break;
-       default:
-               filename = AR6003_REV3_PATCH_FILE;
-               break;
-       }
  
-       if (ar->fw_patch == NULL) {
-               ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
-                                   &ar->fw_patch_len);
-               if (ret) {
-                       ath6kl_err("Failed to get patch file %s: %d\n",
-                                  filename, ret);
-                       return ret;
-               }
+       if (ar->hw.fw_patch == NULL)
+               return 0;
+       filename = ar->hw.fw_patch;
+       ret = ath6kl_get_fw(ar, filename, &ar->fw_patch,
+                           &ar->fw_patch_len);
+       if (ret) {
+               ath6kl_err("Failed to get patch file %s: %d\n",
+                          filename, ret);
+               return ret;
        }
  
        return 0;
@@@ -811,19 -845,10 +845,10 @@@ static int ath6kl_fetch_fw_api2(struct 
        int ret, ie_id, i, index, bit;
        __le32 *val;
  
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               filename = AR6003_REV2_FIRMWARE_2_FILE;
-               break;
-       case AR6003_REV3_VERSION:
-               filename = AR6003_REV3_FIRMWARE_2_FILE;
-               break;
-       case AR6004_REV1_VERSION:
-               filename = AR6004_REV1_FIRMWARE_2_FILE;
-               break;
-       default:
+       if (ar->hw.fw_api2 == NULL)
                return -EOPNOTSUPP;
-       }
+       filename = ar->hw.fw_api2;
  
        ret = request_firmware(&fw, filename, ar->dev);
        if (ret)
                                   ar->hw.reserved_ram_size);
                        break;
                case ATH6KL_FW_IE_CAPABILITIES:
+                       if (ie_len < DIV_ROUND_UP(ATH6KL_FW_CAPABILITY_MAX, 8))
+                               break;
                        ath6kl_dbg(ATH6KL_DBG_BOOT,
                                   "found firmware capabilities ie (%zd B)\n",
                                   ie_len);
  
                        for (i = 0; i < ATH6KL_FW_CAPABILITY_MAX; i++) {
-                               index = ALIGN(i, 8) / 8;
+                               index = i / 8;
                                bit = i % 8;
  
                                if (data[index] & (1 << bit))
                        ar->hw.dataset_patch_addr = le32_to_cpup(val);
  
                        ath6kl_dbg(ATH6KL_DBG_BOOT,
-                                  "found patch address ie 0x%d\n",
+                                  "found patch address ie 0x%x\n",
                                   ar->hw.dataset_patch_addr);
                        break;
+               case ATH6KL_FW_IE_BOARD_ADDR:
+                       if (ie_len != sizeof(*val))
+                               break;
+                       val = (__le32 *) data;
+                       ar->hw.board_addr = le32_to_cpup(val);
+                       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                                  "found board address ie 0x%x\n",
+                                  ar->hw.board_addr);
+                       break;
+               case ATH6KL_FW_IE_VIF_MAX:
+                       if (ie_len != sizeof(*val))
+                               break;
+                       val = (__le32 *) data;
+                       ar->vif_max = min_t(unsigned int, le32_to_cpup(val),
+                                           ATH6KL_VIF_MAX);
+                       if (ar->vif_max > 1 && !ar->p2p)
+                               ar->max_norm_iface = 2;
+                       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                                  "found vif max ie %d\n", ar->vif_max);
+                       break;
                default:
                        ath6kl_dbg(ATH6KL_DBG_BOOT, "Unknown fw ie: %u\n",
                                   le32_to_cpup(&hdr->id));
@@@ -994,8 -1047,8 +1047,8 @@@ static int ath6kl_upload_board_file(str
         * For AR6004, host determine Target RAM address for
         * writing board data.
         */
-       if (ar->target_type == TARGET_TYPE_AR6004) {
-               board_address = AR6004_REV1_BOARD_DATA_ADDRESS;
+       if (ar->hw.board_addr != 0) {
+               board_address = ar->hw.board_addr;
                ath6kl_bmi_write(ar,
                                ath6kl_get_hi_item_addr(ar,
                                HI_ITEM(hi_board_data)),
                        HI_ITEM(hi_board_ext_data)),
                        (u8 *) &board_ext_address, 4);
  
-       if (board_ext_address == 0) {
+       if (ar->target_type == TARGET_TYPE_AR6003 &&
+           board_ext_address == 0) {
                ath6kl_err("Failed to get board file target address.\n");
                return -EINVAL;
        }
                break;
        }
  
-       if (ar->fw_board_len == (board_data_size +
-                                board_ext_data_size)) {
+       if (board_ext_address &&
+           ar->fw_board_len == (board_data_size + board_ext_data_size)) {
  
                /* write extended board data */
                ath6kl_dbg(ATH6KL_DBG_BOOT,
@@@ -1092,8 -1146,8 +1146,8 @@@ static int ath6kl_upload_otp(struct ath
        bool from_hw = false;
        int ret;
  
-       if (WARN_ON(ar->fw_otp == NULL))
-               return -ENOENT;
+       if (ar->fw_otp == NULL)
+               return 0;
  
        address = ar->hw.app_load_addr;
  
@@@ -1142,7 -1196,7 +1196,7 @@@ static int ath6kl_upload_firmware(struc
        int ret;
  
        if (WARN_ON(ar->fw == NULL))
-               return -ENOENT;
+               return 0;
  
        address = ar->hw.app_load_addr;
  
@@@ -1172,8 -1226,8 +1226,8 @@@ static int ath6kl_upload_patch(struct a
        u32 address, param;
        int ret;
  
-       if (WARN_ON(ar->fw_patch == NULL))
-               return -ENOENT;
+       if (ar->fw_patch == NULL)
+               return 0;
  
        address = ar->hw.dataset_patch_addr;
  
@@@ -1258,7 -1312,7 +1312,7 @@@ static int ath6kl_init_upload(struct at
                return status;
  
        /* WAR to avoid SDIO CRC err */
-       if (ar->version.target_ver == AR6003_REV2_VERSION) {
+       if (ar->version.target_ver == AR6003_HW_2_0_VERSION) {
                ath6kl_err("temporary war to avoid sdio crc error\n");
  
                param = 0x20;
        if (status)
                return status;
  
-       /* Configure GPIO AR6003 UART */
-       param = CONFIG_AR600x_DEBUG_UART_TX_PIN;
-       status = ath6kl_bmi_write(ar,
-                                 ath6kl_get_hi_item_addr(ar,
-                                 HI_ITEM(hi_dbg_uart_txpin)),
-                                 (u8 *)&param, 4);
        return status;
  }
  
  static int ath6kl_init_hw_params(struct ath6kl *ar)
  {
-       switch (ar->version.target_ver) {
-       case AR6003_REV2_VERSION:
-               ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
-               ar->hw.app_load_addr = AR6003_REV2_APP_LOAD_ADDRESS;
-               ar->hw.board_ext_data_addr = AR6003_REV2_BOARD_EXT_DATA_ADDRESS;
-               ar->hw.reserved_ram_size = AR6003_REV2_RAM_RESERVE_SIZE;
+       const struct ath6kl_hw *hw;
+       int i;
  
-               /* hw2.0 needs override address hardcoded */
-               ar->hw.app_start_override_addr = 0x944C00;
+       for (i = 0; i < ARRAY_SIZE(hw_list); i++) {
+               hw = &hw_list[i];
  
-               break;
-       case AR6003_REV3_VERSION:
-               ar->hw.dataset_patch_addr = AR6003_REV3_DATASET_PATCH_ADDRESS;
-               ar->hw.app_load_addr = 0x1234;
-               ar->hw.board_ext_data_addr = AR6003_REV3_BOARD_EXT_DATA_ADDRESS;
-               ar->hw.reserved_ram_size = AR6003_REV3_RAM_RESERVE_SIZE;
-               break;
-       case AR6004_REV1_VERSION:
-               ar->hw.dataset_patch_addr = AR6003_REV2_DATASET_PATCH_ADDRESS;
-               ar->hw.app_load_addr = AR6003_REV3_APP_LOAD_ADDRESS;
-               ar->hw.board_ext_data_addr = AR6004_REV1_BOARD_EXT_DATA_ADDRESS;
-               ar->hw.reserved_ram_size = AR6004_REV1_RAM_RESERVE_SIZE;
-               break;
-       default:
+               if (hw->id == ar->version.target_ver)
+                       break;
+       }
+       if (i == ARRAY_SIZE(hw_list)) {
                ath6kl_err("Unsupported hardware version: 0x%x\n",
                           ar->version.target_ver);
                return -EINVAL;
        }
  
+       ar->hw = *hw;
        ath6kl_dbg(ATH6KL_DBG_BOOT,
                   "target_ver 0x%x target_type 0x%x dataset_patch 0x%x app_load_addr 0x%x\n",
                   ar->version.target_ver, ar->target_type,
                   "app_start_override_addr 0x%x board_ext_data_addr 0x%x reserved_ram_size 0x%x",
                   ar->hw.app_start_override_addr, ar->hw.board_ext_data_addr,
                   ar->hw.reserved_ram_size);
+       ath6kl_dbg(ATH6KL_DBG_BOOT,
+                  "refclk_hz %d uarttx_pin %d",
+                  ar->hw.refclk_hz, ar->hw.uarttx_pin);
  
        return 0;
  }
  
+ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)
+ {
+       switch (type) {
+       case ATH6KL_HIF_TYPE_SDIO:
+               return "sdio";
+       case ATH6KL_HIF_TYPE_USB:
+               return "usb";
+       }
+       return NULL;
+ }
  int ath6kl_init_hw_start(struct ath6kl *ar)
  {
        long timeleft;
  
        ath6kl_dbg(ATH6KL_DBG_BOOT, "firmware booted\n");
  
+       if (test_and_clear_bit(FIRST_BOOT, &ar->flag)) {
+               ath6kl_info("%s %s fw %s%s\n",
+                           ar->hw.name,
+                           ath6kl_init_get_hif_name(ar->hif_type),
+                           ar->wiphy->fw_version,
+                           test_bit(TESTMODE, &ar->flag) ? " testmode" : "");
+       }
        if (ar->version.abi_ver != ATH6KL_ABI_VERSION) {
                ath6kl_err("abi version mismatch: host(0x%x), target(0x%x)\n",
                           ATH6KL_ABI_VERSION, ar->version.abi_ver);
        if ((ath6kl_set_host_app_area(ar)) != 0)
                ath6kl_err("unable to set the host app area\n");
  
-       for (i = 0; i < MAX_NUM_VIF; i++) {
+       for (i = 0; i < ar->vif_max; i++) {
                ret = ath6kl_target_config_wlan_params(ar, i);
                if (ret)
                        goto err_htc_stop;
@@@ -1558,7 -1618,7 +1618,7 @@@ int ath6kl_core_init(struct ath6kl *ar
                goto err_node_cleanup;
        }
  
-       for (i = 0; i < MAX_NUM_VIF; i++)
+       for (i = 0; i < ar->vif_max; i++)
                ar->avail_idx_map |= BIT(i);
  
        rtnl_lock();
  
        ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_FW_ROAM |
                            WIPHY_FLAG_HAVE_AP_SME |
-                           WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
+                           WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
+                           WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
+       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
+               ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
+       ar->wiphy->probe_resp_offload =
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_WPS2 |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_P2P |
+               NL80211_PROBE_RESP_OFFLOAD_SUPPORT_80211U;
  
        set_bit(FIRST_BOOT, &ar->flag);
  
index 9681c099d0a597ec7bd906865458673b63690748,f57084ec49e755f5b426afd964eef0ca53d109b9..619b95d764ff33ea0adceabd8a15cb5c93815f1e
@@@ -121,8 -121,7 +121,7 @@@ static bool ath9k_hw_def_fill_eeprom(st
        struct ath_common *common = ath9k_hw_common(ah);
  
        if (!ath9k_hw_use_flash(ah)) {
-               ath_dbg(common, ATH_DBG_EEPROM,
-                       "Reading from EEPROM, not flash\n");
+               ath_dbg(common, EEPROM, "Reading from EEPROM, not flash\n");
        }
  
        if (common->bus_ops->ath_bus_type == ATH_USB)
@@@ -279,8 -278,7 +278,7 @@@ static int ath9k_hw_def_check_eeprom(st
        }
  
        if (!ath9k_hw_use_flash(ah)) {
-               ath_dbg(common, ATH_DBG_EEPROM,
-                       "Read Magic = 0x%04X\n", magic);
+               ath_dbg(common, EEPROM, "Read Magic = 0x%04X\n", magic);
  
                if (magic != AR5416_EEPROM_MAGIC) {
                        magic2 = swab16(magic);
                }
        }
  
-       ath_dbg(common, ATH_DBG_EEPROM, "need_swap = %s.\n",
+       ath_dbg(common, EEPROM, "need_swap = %s\n",
                need_swap ? "True" : "False");
  
        if (need_swap)
                u32 integer, j;
                u16 word;
  
-               ath_dbg(common, ATH_DBG_EEPROM,
+               ath_dbg(common, EEPROM,
                        "EEPROM Endianness is not native.. Changing.\n");
  
                word = swab16(eep->baseEepHeader.length);
        if ((ah->hw_version.devid == AR9280_DEVID_PCI) &&
            ((eep->baseEepHeader.version & 0xff) > 0x0a) &&
            (eep->baseEepHeader.pwdclkind == 0))
 -              ah->need_an_top2_fixup = 1;
 +              ah->need_an_top2_fixup = true;
  
        if ((common->bus_ops->ath_bus_type == ATH_USB) &&
            (AR_SREV_9280(ah)))
@@@ -965,15 -963,12 +963,12 @@@ static void ath9k_hw_set_def_power_cal_
                                reg32 = get_unaligned_le32(&pdadcValues[4 * j]);
                                REG_WRITE(ah, regOffset, reg32);
  
-                               ath_dbg(common, ATH_DBG_EEPROM,
+                               ath_dbg(common, EEPROM,
                                        "PDADC (%d,%4x): %4.4x %8.8x\n",
                                        i, regChainOffset, regOffset,
                                        reg32);
-                               ath_dbg(common, ATH_DBG_EEPROM,
-                                       "PDADC: Chain %d | PDADC %3d "
-                                       "Value %3d | PDADC %3d Value %3d | "
-                                       "PDADC %3d Value %3d | PDADC %3d "
-                                       "Value %3d |\n",
+                               ath_dbg(common, EEPROM,
+                                       "PDADC: Chain %d | PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d Value %3d | PDADC %3d Value %3d |\n",
                                        i, 4 * j, pdadcValues[4 * j],
                                        4 * j + 1, pdadcValues[4 * j + 1],
                                        4 * j + 2, pdadcValues[4 * j + 2],
@@@ -1278,7 -1273,7 +1273,7 @@@ static void ath9k_hw_def_set_txpower(st
                regulatory->max_power_level += INCREASE_MAXPOW_BY_THREE_CHAIN;
                break;
        default:
-               ath_dbg(ath9k_hw_common(ah), ATH_DBG_EEPROM,
+               ath_dbg(ath9k_hw_common(ah), EEPROM,
                        "Invalid chainmask configuration\n");
                break;
        }
@@@ -1396,8 -1391,7 +1391,7 @@@ static u16 ath9k_hw_def_get_spur_channe
  
        u16 spur_val = AR_NO_SPUR;
  
-       ath_dbg(common, ATH_DBG_ANI,
-               "Getting spur idx:%d is2Ghz:%d val:%x\n",
+       ath_dbg(common, ANI, "Getting spur idx:%d is2Ghz:%d val:%x\n",
                i, is2GHz, ah->config.spurchans[i][is2GHz]);
  
        switch (ah->config.spurmode) {
                break;
        case SPUR_ENABLE_IOCTL:
                spur_val = ah->config.spurchans[i][is2GHz];
-               ath_dbg(common, ATH_DBG_ANI,
-                       "Getting spur val from new loc. %d\n", spur_val);
+               ath_dbg(common, ANI, "Getting spur val from new loc. %d\n",
+                       spur_val);
                break;
        case SPUR_ENABLE_EEPROM:
                spur_val = EEP_DEF_SPURCHAN;
index 2622fcee8c96fab2ee199c55c007ecdbe4745871,b092523caedeb3c7aa75a5b2e03147837569d367..9aa01997b1ead43231bc04c4ce59801495dafc09
@@@ -104,6 -104,29 +104,29 @@@ static int ath_max_4ms_framelen[4][32] 
  /* Aggregation logic */
  /*********************/
  
+ static void ath_txq_lock(struct ath_softc *sc, struct ath_txq *txq)
+ {
+       spin_lock_bh(&txq->axq_lock);
+ }
+ static void ath_txq_unlock(struct ath_softc *sc, struct ath_txq *txq)
+ {
+       spin_unlock_bh(&txq->axq_lock);
+ }
+ static void ath_txq_unlock_complete(struct ath_softc *sc, struct ath_txq *txq)
+ {
+       struct sk_buff_head q;
+       struct sk_buff *skb;
+       __skb_queue_head_init(&q);
+       skb_queue_splice_init(&txq->complete_q, &q);
+       spin_unlock_bh(&txq->axq_lock);
+       while ((skb = __skb_dequeue(&q)))
+               ieee80211_tx_status(sc->hw, skb);
+ }
  static void ath_tx_queue_tid(struct ath_txq *txq, struct ath_atx_tid *tid)
  {
        struct ath_atx_ac *ac = tid->ac;
@@@ -130,7 -153,7 +153,7 @@@ static void ath_tx_resume_tid(struct at
  
        WARN_ON(!tid->paused);
  
-       spin_lock_bh(&txq->axq_lock);
+       ath_txq_lock(sc, txq);
        tid->paused = false;
  
        if (skb_queue_empty(&tid->buf_q))
        ath_tx_queue_tid(txq, tid);
        ath_txq_schedule(sc, txq);
  unlock:
-       spin_unlock_bh(&txq->axq_lock);
+       ath_txq_unlock_complete(sc, txq);
  }
  
  static struct ath_frame_info *get_frame_info(struct sk_buff *skb)
@@@ -189,8 -212,11 +212,11 @@@ static void ath_tx_flush_tid(struct ath
                tid->state &= ~AGGR_CLEANUP;
        }
  
-       if (sendbar)
+       if (sendbar) {
+               ath_txq_unlock(sc, txq);
                ath_send_bar(tid, tid->seq_start);
+               ath_txq_lock(sc, txq);
+       }
  }
  
  static void ath_tx_update_baw(struct ath_softc *sc, struct ath_atx_tid *tid,
@@@ -554,13 -580,6 +580,6 @@@ static void ath_tx_complete_aggr(struc
                bf = bf_next;
        }
  
-       if (bar_index >= 0) {
-               u16 bar_seq = ATH_BA_INDEX2SEQ(seq_first, bar_index);
-               ath_send_bar(tid, ATH_BA_INDEX2SEQ(seq_first, bar_index + 1));
-               if (BAW_WITHIN(tid->seq_start, tid->baw_size, bar_seq))
-                       tid->bar_index = ATH_BA_INDEX(tid->seq_start, bar_seq);
-       }
        /* prepend un-acked frames to the beginning of the pending frame queue */
        if (!skb_queue_empty(&bf_pending)) {
                if (an->sleeping)
                }
        }
  
+       if (bar_index >= 0) {
+               u16 bar_seq = ATH_BA_INDEX2SEQ(seq_first, bar_index);
+               if (BAW_WITHIN(tid->seq_start, tid->baw_size, bar_seq))
+                       tid->bar_index = ATH_BA_INDEX(tid->seq_start, bar_seq);
+               ath_txq_unlock(sc, txq);
+               ath_send_bar(tid, ATH_BA_INDEX2SEQ(seq_first, bar_index + 1));
+               ath_txq_lock(sc, txq);
+       }
        if (tid->state & AGGR_CLEANUP)
                ath_tx_flush_tid(sc, tid);
  
@@@ -1172,7 -1202,7 +1202,7 @@@ void ath_tx_aggr_stop(struct ath_softc 
                return;
        }
  
-       spin_lock_bh(&txq->axq_lock);
+       ath_txq_lock(sc, txq);
        txtid->paused = true;
  
        /*
                txtid->state &= ~AGGR_ADDBA_COMPLETE;
  
        ath_tx_flush_tid(sc, txtid);
-       spin_unlock_bh(&txq->axq_lock);
+       ath_txq_unlock_complete(sc, txq);
  }
  
  void ath_tx_aggr_sleep(struct ieee80211_sta *sta, struct ath_softc *sc,
                ac = tid->ac;
                txq = ac->txq;
  
-               spin_lock_bh(&txq->axq_lock);
+               ath_txq_lock(sc, txq);
  
                buffered = !skb_queue_empty(&tid->buf_q);
  
                        list_del(&ac->list);
                }
  
-               spin_unlock_bh(&txq->axq_lock);
+               ath_txq_unlock(sc, txq);
  
                ieee80211_sta_set_buffered(sta, tidno, buffered);
        }
@@@ -1239,7 -1269,7 +1269,7 @@@ void ath_tx_aggr_wakeup(struct ath_soft
                ac = tid->ac;
                txq = ac->txq;
  
-               spin_lock_bh(&txq->axq_lock);
+               ath_txq_lock(sc, txq);
                ac->clear_ps_filter = true;
  
                if (!skb_queue_empty(&tid->buf_q) && !tid->paused) {
                        ath_txq_schedule(sc, txq);
                }
  
-               spin_unlock_bh(&txq->axq_lock);
+               ath_txq_unlock_complete(sc, txq);
        }
  }
  
@@@ -1347,6 -1377,7 +1377,7 @@@ struct ath_txq *ath_txq_setup(struct at
                txq->axq_qnum = axq_qnum;
                txq->mac80211_qnum = -1;
                txq->axq_link = NULL;
+               __skb_queue_head_init(&txq->complete_q);
                INIT_LIST_HEAD(&txq->axq_q);
                INIT_LIST_HEAD(&txq->axq_acq);
                spin_lock_init(&txq->axq_lock);
@@@ -1471,7 -1502,8 +1502,8 @@@ static void ath_drain_txq_list(struct a
   */
  void ath_draintxq(struct ath_softc *sc, struct ath_txq *txq, bool retry_tx)
  {
-       spin_lock_bh(&txq->axq_lock);
+       ath_txq_lock(sc, txq);
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_EDMA) {
                int idx = txq->txq_tailidx;
  
        if ((sc->sc_flags & SC_OP_TXAGGR) && !retry_tx)
                ath_txq_drain_pending_buffers(sc, txq);
  
-       spin_unlock_bh(&txq->axq_lock);
+       ath_txq_unlock_complete(sc, txq);
  }
  
  bool ath_drain_all_txq(struct ath_softc *sc, bool retry_tx)
@@@ -1626,8 -1658,8 +1658,8 @@@ static void ath_tx_txqaddbuf(struct ath
        bf = list_first_entry(head, struct ath_buf, list);
        bf_last = list_entry(head->prev, struct ath_buf, list);
  
-       ath_dbg(common, ATH_DBG_QUEUE,
-               "qnum: %d, txq depth: %d\n", txq->axq_qnum, txq->axq_depth);
+       ath_dbg(common, QUEUE, "qnum: %d, txq depth: %d\n",
+               txq->axq_qnum, txq->axq_depth);
  
        if (edma && list_empty(&txq->txq_fifo[txq->txq_headidx])) {
                list_splice_tail_init(head, &txq->txq_fifo[txq->txq_headidx]);
  
                if (txq->axq_link) {
                        ath9k_hw_set_desc_link(ah, txq->axq_link, bf->bf_daddr);
-                       ath_dbg(common, ATH_DBG_XMIT,
-                               "link[%u] (%p)=%llx (%p)\n",
+                       ath_dbg(common, XMIT, "link[%u] (%p)=%llx (%p)\n",
                                txq->axq_qnum, txq->axq_link,
                                ito64(bf->bf_daddr), bf->bf_desc);
                } else if (!edma)
        if (puttxbuf) {
                TX_STAT_INC(txq->axq_qnum, puttxbuf);
                ath9k_hw_puttxbuf(ah, txq->axq_qnum, bf->bf_daddr);
-               ath_dbg(common, ATH_DBG_XMIT, "TXDP[%u] = %llx (%p)\n",
+               ath_dbg(common, XMIT, "TXDP[%u] = %llx (%p)\n",
                        txq->axq_qnum, ito64(bf->bf_daddr), bf->bf_desc);
        }
  
@@@ -1793,7 -1824,7 +1824,7 @@@ static struct ath_buf *ath_tx_setup_buf
  
        bf = ath_tx_get_buffer(sc);
        if (!bf) {
-               ath_dbg(common, ATH_DBG_XMIT, "TX buffers are full\n");
+               ath_dbg(common, XMIT, "TX buffers are full\n");
                goto error;
        }
  
@@@ -1925,16 -1956,17 +1956,17 @@@ int ath_tx_start(struct ieee80211_hw *h
         */
  
        q = skb_get_queue_mapping(skb);
-       spin_lock_bh(&txq->axq_lock);
+       ath_txq_lock(sc, txq);
        if (txq == sc->tx.txq_map[q] &&
            ++txq->pending_frames > ATH_MAX_QDEPTH && !txq->stopped) {
                ieee80211_stop_queue(sc->hw, q);
 -              txq->stopped = 1;
 +              txq->stopped = true;
        }
  
        ath_tx_start_dma(sc, skb, txctl);
  
-       spin_unlock_bh(&txq->axq_lock);
+       ath_txq_unlock(sc, txq);
  
        return 0;
  }
  static void ath_tx_complete(struct ath_softc *sc, struct sk_buff *skb,
                            int tx_flags, struct ath_txq *txq)
  {
-       struct ieee80211_hw *hw = sc->hw;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(skb);
        struct ath_common *common = ath9k_hw_common(sc->sc_ah);
        struct ieee80211_hdr * hdr = (struct ieee80211_hdr *)skb->data;
        int q, padpos, padsize;
  
-       ath_dbg(common, ATH_DBG_XMIT, "TX complete: skb: %p\n", skb);
+       ath_dbg(common, XMIT, "TX complete: skb: %p\n", skb);
  
        if (!(tx_flags & ATH_TX_ERROR))
                /* Frame was ACKed */
  
        if ((sc->ps_flags & PS_WAIT_FOR_TX_ACK) && !txq->axq_depth) {
                sc->ps_flags &= ~PS_WAIT_FOR_TX_ACK;
-               ath_dbg(common, ATH_DBG_PS,
+               ath_dbg(common, PS,
                        "Going back to sleep after having received TX status (0x%lx)\n",
                        sc->ps_flags & (PS_WAIT_FOR_BEACON |
                                        PS_WAIT_FOR_CAB |
  
                if (txq->stopped && txq->pending_frames < ATH_MAX_QDEPTH) {
                        ieee80211_wake_queue(sc->hw, q);
 -                      txq->stopped = 0;
 +                      txq->stopped = false;
                }
        }
  
-       ieee80211_tx_status(hw, skb);
+       __skb_queue_tail(&txq->complete_q, skb);
  }
  
  static void ath_tx_complete_buf(struct ath_softc *sc, struct ath_buf *bf,
@@@ -2122,11 -2153,11 +2153,11 @@@ static void ath_tx_processq(struct ath_
        struct ath_tx_status ts;
        int status;
  
-       ath_dbg(common, ATH_DBG_QUEUE, "tx queue %d (%x), link %p\n",
+       ath_dbg(common, QUEUE, "tx queue %d (%x), link %p\n",
                txq->axq_qnum, ath9k_hw_gettxbuf(sc->sc_ah, txq->axq_qnum),
                txq->axq_link);
  
-       spin_lock_bh(&txq->axq_lock);
+       ath_txq_lock(sc, txq);
        for (;;) {
                if (work_pending(&sc->hw_reset_work))
                        break;
  
                ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
        }
-       spin_unlock_bh(&txq->axq_lock);
+       ath_txq_unlock_complete(sc, txq);
  }
  
  static void ath_tx_complete_poll_work(struct work_struct *work)
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
                if (ATH_TXQ_SETUP(sc, i)) {
                        txq = &sc->tx.txq[i];
-                       spin_lock_bh(&txq->axq_lock);
+                       ath_txq_lock(sc, txq);
                        if (txq->axq_depth) {
                                if (txq->axq_tx_inprogress) {
                                        needreset = true;
-                                       spin_unlock_bh(&txq->axq_lock);
+                                       ath_txq_unlock(sc, txq);
                                        break;
                                } else {
                                        txq->axq_tx_inprogress = true;
                                }
                        }
-                       spin_unlock_bh(&txq->axq_lock);
+                       ath_txq_unlock_complete(sc, txq);
                }
  
        if (needreset) {
-               ath_dbg(ath9k_hw_common(sc->sc_ah), ATH_DBG_RESET,
+               ath_dbg(ath9k_hw_common(sc->sc_ah), RESET,
                        "tx hung, resetting the chip\n");
                RESET_STAT_INC(sc, RESET_TYPE_TX_HANG);
                ieee80211_queue_work(sc->hw, &sc->hw_reset_work);
@@@ -2259,8 -2290,7 +2290,7 @@@ void ath_tx_edma_tasklet(struct ath_sof
                if (status == -EINPROGRESS)
                        break;
                if (status == -EIO) {
-                       ath_dbg(common, ATH_DBG_XMIT,
-                               "Error processing tx status\n");
+                       ath_dbg(common, XMIT, "Error processing tx status\n");
                        break;
                }
  
  
                txq = &sc->tx.txq[ts.qid];
  
-               spin_lock_bh(&txq->axq_lock);
+               ath_txq_lock(sc, txq);
  
                if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
-                       spin_unlock_bh(&txq->axq_lock);
+                       ath_txq_unlock(sc, txq);
                        return;
                }
  
                }
  
                ath_tx_process_buffer(sc, txq, &ts, bf, &bf_head);
-               spin_unlock_bh(&txq->axq_lock);
+               ath_txq_unlock_complete(sc, txq);
        }
  }
  
@@@ -2437,7 -2467,7 +2467,7 @@@ void ath_tx_node_cleanup(struct ath_sof
                ac = tid->ac;
                txq = ac->txq;
  
-               spin_lock_bh(&txq->axq_lock);
+               ath_txq_lock(sc, txq);
  
                if (tid->sched) {
                        list_del(&tid->list);
                tid->state &= ~AGGR_ADDBA_COMPLETE;
                tid->state &= ~AGGR_CLEANUP;
  
-               spin_unlock_bh(&txq->axq_lock);
+               ath_txq_unlock(sc, txq);
        }
  }
index af23968520b61806435c71b59ec8ce7726535b35,56d37dc967aae08be1199aa7280c4fdbb9e90a0e..b5f1b91002bbe609cf2a1d97e127d52f7baf32e4
@@@ -890,7 -890,7 +890,7 @@@ struct b43_dmaring *b43_setup_dmaring(s
        else
                ring->ops = &dma32_ops;
        if (for_tx) {
 -              ring->tx = 1;
 +              ring->tx = true;
                ring->current_slot = -1;
        } else {
                if (ring->index == 0) {
@@@ -1061,7 -1061,7 +1061,7 @@@ void b43_dma_free(struct b43_wldev *dev
  static int b43_dma_set_mask(struct b43_wldev *dev, u64 mask)
  {
        u64 orig_mask = mask;
 -      bool fallback = 0;
 +      bool fallback = false;
        int err;
  
        /* Try to set the DMA mask. If it fails, try falling back to a
                }
                if (mask == DMA_BIT_MASK(64)) {
                        mask = DMA_BIT_MASK(32);
 -                      fallback = 1;
 +                      fallback = true;
                        continue;
                }
                if (mask == DMA_BIT_MASK(32)) {
                        mask = DMA_BIT_MASK(30);
 -                      fallback = 1;
 +                      fallback = true;
                        continue;
                }
                b43err(dev->wl, "The machine/kernel does not support "
@@@ -1307,7 -1307,7 +1307,7 @@@ static int dma_tx_fragment(struct b43_d
        memset(meta, 0, sizeof(*meta));
  
        meta->skb = skb;
 -      meta->is_last_fragment = 1;
 +      meta->is_last_fragment = true;
        priv_info->bouncebuffer = NULL;
  
        meta->dmaaddr = map_descbuffer(ring, skb->data, skb->len, 1);
@@@ -1465,8 -1465,10 +1465,10 @@@ int b43_dma_tx(struct b43_wldev *dev, s
        if ((free_slots(ring) < TX_SLOTS_PER_FRAME) ||
            should_inject_overflow(ring)) {
                /* This TX ring is full. */
-               ieee80211_stop_queue(dev->wl->hw, skb_get_queue_mapping(skb));
+               unsigned int skb_mapping = skb_get_queue_mapping(skb);
+               ieee80211_stop_queue(dev->wl->hw, skb_mapping);
+               dev->wl->tx_queue_stopped[skb_mapping] = 1;
 -              ring->stopped = 1;
 +              ring->stopped = true;
                if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
                        b43dbg(dev->wl, "Stopped TX ring %d\n", ring->index);
                }
@@@ -1584,12 -1586,21 +1586,21 @@@ void b43_dma_handle_txstatus(struct b43
        }
        if (ring->stopped) {
                B43_WARN_ON(free_slots(ring) < TX_SLOTS_PER_FRAME);
-               ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
 -              ring->stopped = 0;
 +              ring->stopped = false;
+       }
+       if (dev->wl->tx_queue_stopped[ring->queue_prio]) {
+               dev->wl->tx_queue_stopped[ring->queue_prio] = 0;
+       } else {
+               /* If the driver queue is running wake the corresponding
+                * mac80211 queue. */
+               ieee80211_wake_queue(dev->wl->hw, ring->queue_prio);
                if (b43_debug(dev, B43_DBG_DMAVERBOSE)) {
                        b43dbg(dev->wl, "Woke up TX ring %d\n", ring->index);
                }
        }
+       /* Add work to the queue. */
+       ieee80211_queue_work(dev->wl->hw, &dev->wl->tx_work);
  }
  
  static void dma_rx(struct b43_dmaring *ring, int *slot)
index c74f36f6e34894d105a1a97bc8cb86fbc8e01aab,989f654de006ae0e095e4c4f093e223812e41fae..1c6f19393efa72037b7369993bf7af463a7bb51a
@@@ -1122,17 -1122,17 +1122,17 @@@ void b43_power_saving_ctl_bits(struct b
        B43_WARN_ON((ps_flags & B43_PS_AWAKE) && (ps_flags & B43_PS_ASLEEP));
  
        if (ps_flags & B43_PS_ENABLED) {
 -              hwps = 1;
 +              hwps = true;
        } else if (ps_flags & B43_PS_DISABLED) {
 -              hwps = 0;
 +              hwps = false;
        } else {
                //TODO: If powersave is not off and FIXME is not set and we are not in adhoc
                //      and thus is not an AP and we are associated, set bit 25
        }
        if (ps_flags & B43_PS_AWAKE) {
 -              awake = 1;
 +              awake = true;
        } else if (ps_flags & B43_PS_ASLEEP) {
 -              awake = 0;
 +              awake = false;
        } else {
                //TODO: If the device is awake or this is an AP, or we are scanning, or FIXME,
                //      or we are associated, or FIXME, or the latest PS-Poll packet sent was
        }
  
  /* FIXME: For now we force awake-on and hwps-off */
 -      hwps = 0;
 -      awake = 1;
 +      hwps = false;
 +      awake = true;
  
        macctl = b43_read32(dev, B43_MMIO_MACCTL);
        if (hwps)
@@@ -1339,7 -1339,7 +1339,7 @@@ static void b43_calculate_link_quality(
                return;
        if (dev->noisecalc.calculation_running)
                return;
 -      dev->noisecalc.calculation_running = 1;
 +      dev->noisecalc.calculation_running = true;
        dev->noisecalc.nr_samples = 0;
  
        b43_generate_noise_sample(dev);
@@@ -1408,7 -1408,7 +1408,7 @@@ static void handle_irq_noise(struct b43
                        average -= 48;
  
                dev->stats.link_noise = average;
 -              dev->noisecalc.calculation_running = 0;
 +              dev->noisecalc.calculation_running = false;
                return;
        }
  generate_new:
@@@ -1424,7 -1424,7 +1424,7 @@@ static void handle_irq_tbtt_indication(
                        b43_power_saving_ctl_bits(dev, 0);
        }
        if (b43_is_mode(dev->wl, NL80211_IFTYPE_ADHOC))
 -              dev->dfq_valid = 1;
 +              dev->dfq_valid = true;
  }
  
  static void handle_irq_atim_end(struct b43_wldev *dev)
                b43_write32(dev, B43_MMIO_MACCMD,
                            b43_read32(dev, B43_MMIO_MACCMD)
                            | B43_MACCMD_DFQ_VALID);
 -              dev->dfq_valid = 0;
 +              dev->dfq_valid = false;
        }
  }
  
@@@ -1539,7 -1539,7 +1539,7 @@@ static void b43_write_beacon_template(s
        unsigned int i, len, variable_len;
        const struct ieee80211_mgmt *bcn;
        const u8 *ie;
 -      bool tim_found = 0;
 +      bool tim_found = false;
        unsigned int rate;
        u16 ctl;
        int antenna;
                        /* A valid TIM is at least 4 bytes long. */
                        if (ie_len < 4)
                                break;
 -                      tim_found = 1;
 +                      tim_found = true;
  
                        tim_position = sizeof(struct b43_plcp_hdr6);
                        tim_position += offsetof(struct ieee80211_mgmt, u.beacon.variable);
@@@ -1625,7 -1625,7 +1625,7 @@@ static void b43_upload_beacon0(struct b
        if (wl->beacon0_uploaded)
                return;
        b43_write_beacon_template(dev, 0x68, 0x18);
 -      wl->beacon0_uploaded = 1;
 +      wl->beacon0_uploaded = true;
  }
  
  static void b43_upload_beacon1(struct b43_wldev *dev)
        if (wl->beacon1_uploaded)
                return;
        b43_write_beacon_template(dev, 0x468, 0x1A);
 -      wl->beacon1_uploaded = 1;
 +      wl->beacon1_uploaded = true;
  }
  
  static void handle_irq_beacon(struct b43_wldev *dev)
        if (unlikely(wl->beacon_templates_virgin)) {
                /* We never uploaded a beacon before.
                 * Upload both templates now, but only mark one valid. */
 -              wl->beacon_templates_virgin = 0;
 +              wl->beacon_templates_virgin = false;
                b43_upload_beacon0(dev);
                b43_upload_beacon1(dev);
                cmd = b43_read32(dev, B43_MMIO_MACCMD);
@@@ -1755,8 -1755,8 +1755,8 @@@ static void b43_update_templates(struc
        if (wl->current_beacon)
                dev_kfree_skb_any(wl->current_beacon);
        wl->current_beacon = beacon;
 -      wl->beacon0_uploaded = 0;
 -      wl->beacon1_uploaded = 0;
 +      wl->beacon0_uploaded = false;
 +      wl->beacon1_uploaded = false;
        ieee80211_queue_work(wl->hw, &wl->beacon_update_trigger);
  }
  
@@@ -1913,7 -1913,7 +1913,7 @@@ static void b43_do_interrupt_thread(str
                        b43err(dev->wl, "This device does not support DMA "
                               "on your system. It will now be switched to PIO.\n");
                        /* Fall back to PIO transfers if we get fatal DMA errors! */
 -                      dev->use_pio = 1;
 +                      dev->use_pio = true;
                        b43_controller_restart(dev, "DMA error");
                        return;
                }
@@@ -2240,12 -2240,12 +2240,12 @@@ static int b43_try_request_fw(struct b4
                filename = NULL;
        else
                goto err_no_pcm;
 -      fw->pcm_request_failed = 0;
 +      fw->pcm_request_failed = false;
        err = b43_do_request_fw(ctx, filename, &fw->pcm);
        if (err == -ENOENT) {
                /* We did not find a PCM file? Not fatal, but
                 * core rev <= 10 must do without hwcrypto then. */
 -              fw->pcm_request_failed = 1;
 +              fw->pcm_request_failed = true;
        } else if (err)
                goto err_load;
  
@@@ -2535,7 -2535,7 +2535,7 @@@ static int b43_upload_microcode(struct 
        dev->wl->hw->queues = dev->wl->mac80211_initially_registered_queues;
        dev->qos_enabled = !!modparam_qos;
        /* Default to firmware/hardware crypto acceleration. */
 -      dev->hwcrypto_enabled = 1;
 +      dev->hwcrypto_enabled = true;
  
        if (dev->fw.opensource) {
                u16 fwcapa;
                if (!(fwcapa & B43_FWCAPA_HWCRYPTO) || dev->fw.pcm_request_failed) {
                        b43info(dev->wl, "Hardware crypto acceleration not supported by firmware\n");
                        /* Disable hardware crypto and fall back to software crypto. */
 -                      dev->hwcrypto_enabled = 0;
 +                      dev->hwcrypto_enabled = false;
                }
                if (!(fwcapa & B43_FWCAPA_QOS)) {
                        b43info(dev->wl, "QoS not supported by firmware\n");
                         * ieee80211_unregister to make sure the networking core can
                         * properly free possible resources. */
                        dev->wl->hw->queues = 1;
 -                      dev->qos_enabled = 0;
 +                      dev->qos_enabled = false;
                }
        } else {
                b43info(dev->wl, "Loading firmware version %u.%u "
@@@ -3361,10 -3361,10 +3361,10 @@@ static int b43_rng_init(struct b43_wl *
        wl->rng.name = wl->rng_name;
        wl->rng.data_read = b43_rng_read;
        wl->rng.priv = (unsigned long)wl;
 -      wl->rng_initialized = 1;
 +      wl->rng_initialized = true;
        err = hwrng_register(&wl->rng);
        if (err) {
 -              wl->rng_initialized = 0;
 +              wl->rng_initialized = false;
                b43err(wl, "Failed to register the random "
                       "number generator (%d)\n", err);
        }
@@@ -3378,6 -3378,7 +3378,7 @@@ static void b43_tx_work(struct work_str
        struct b43_wl *wl = container_of(work, struct b43_wl, tx_work);
        struct b43_wldev *dev;
        struct sk_buff *skb;
+       int queue_num;
        int err = 0;
  
        mutex_lock(&wl->mutex);
                return;
        }
  
-       while (skb_queue_len(&wl->tx_queue)) {
-               skb = skb_dequeue(&wl->tx_queue);
+       for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
+               while (skb_queue_len(&wl->tx_queue[queue_num])) {
+                       skb = skb_dequeue(&wl->tx_queue[queue_num]);
+                       if (b43_using_pio_transfers(dev))
+                               err = b43_pio_tx(dev, skb);
+                       else
+                               err = b43_dma_tx(dev, skb);
+                       if (err == -ENOSPC) {
+                               wl->tx_queue_stopped[queue_num] = 1;
+                               ieee80211_stop_queue(wl->hw, queue_num);
+                               skb_queue_head(&wl->tx_queue[queue_num], skb);
+                               break;
+                       }
+                       if (unlikely(err))
+                               dev_kfree_skb(skb); /* Drop it */
+                       err = 0;
+               }
  
-               if (b43_using_pio_transfers(dev))
-                       err = b43_pio_tx(dev, skb);
-               else
-                       err = b43_dma_tx(dev, skb);
-               if (unlikely(err))
-                       dev_kfree_skb(skb); /* Drop it */
+               if (!err)
+                       wl->tx_queue_stopped[queue_num] = 0;
        }
  
  #if B43_DEBUG
@@@ -3416,8 -3428,12 +3428,12 @@@ static void b43_op_tx(struct ieee80211_
        }
        B43_WARN_ON(skb_shinfo(skb)->nr_frags);
  
-       skb_queue_tail(&wl->tx_queue, skb);
-       ieee80211_queue_work(wl->hw, &wl->tx_work);
+       skb_queue_tail(&wl->tx_queue[skb->queue_mapping], skb);
+       if (!wl->tx_queue_stopped[skb->queue_mapping]) {
+               ieee80211_queue_work(wl->hw, &wl->tx_work);
+       } else {
+               ieee80211_stop_queue(wl->hw, skb->queue_mapping);
+       }
  }
  
  static void b43_qos_params_upload(struct b43_wldev *dev,
@@@ -3702,13 -3718,13 +3718,13 @@@ static int b43_switch_band(struct b43_w
                case IEEE80211_BAND_5GHZ:
                        if (d->phy.supports_5ghz) {
                                up_dev = d;
 -                              gmode = 0;
 +                              gmode = false;
                        }
                        break;
                case IEEE80211_BAND_2GHZ:
                        if (d->phy.supports_2ghz) {
                                up_dev = d;
 -                              gmode = 1;
 +                              gmode = true;
                        }
                        break;
                default:
@@@ -4147,6 -4163,7 +4163,7 @@@ static struct b43_wldev * b43_wireless_
        struct b43_wl *wl;
        struct b43_wldev *orig_dev;
        u32 mask;
+       int queue_num;
  
        if (!dev)
                return NULL;
@@@ -4199,9 -4216,11 +4216,11 @@@ redo
        mask = b43_read32(dev, B43_MMIO_GEN_IRQ_MASK);
        B43_WARN_ON(mask != 0xFFFFFFFF && mask);
  
-       /* Drain the TX queue */
-       while (skb_queue_len(&wl->tx_queue))
-               dev_kfree_skb(skb_dequeue(&wl->tx_queue));
+       /* Drain all TX queues. */
+       for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
+               while (skb_queue_len(&wl->tx_queue[queue_num]))
+                       dev_kfree_skb(skb_dequeue(&wl->tx_queue[queue_num]));
+       }
  
        b43_mac_suspend(dev);
        b43_leds_exit(dev);
@@@ -4425,18 -4444,18 +4444,18 @@@ static void setup_struct_phy_for_init(s
        atomic_set(&phy->txerr_cnt, B43_PHY_TX_BADNESS_LIMIT);
  
  #if B43_DEBUG
 -      phy->phy_locked = 0;
 -      phy->radio_locked = 0;
 +      phy->phy_locked = false;
 +      phy->radio_locked = false;
  #endif
  }
  
  static void setup_struct_wldev_for_init(struct b43_wldev *dev)
  {
 -      dev->dfq_valid = 0;
 +      dev->dfq_valid = false;
  
        /* 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;
 +      dev->radio_hw_enable = true;
  
        /* Stats */
        memset(&dev->stats, 0, sizeof(dev->stats));
@@@ -4670,16 -4689,16 +4689,16 @@@ static int b43_wireless_core_init(struc
  
        if (b43_bus_host_is_pcmcia(dev->dev) ||
            b43_bus_host_is_sdio(dev->dev)) {
 -              dev->__using_pio_transfers = 1;
 +              dev->__using_pio_transfers = true;
                err = b43_pio_init(dev);
        } else if (dev->use_pio) {
                b43warn(dev->wl, "Forced PIO by use_pio module parameter. "
                        "This should not be needed and will result in lower "
                        "performance.\n");
 -              dev->__using_pio_transfers = 1;
 +              dev->__using_pio_transfers = true;
                err = b43_pio_init(dev);
        } else {
 -              dev->__using_pio_transfers = 0;
 +              dev->__using_pio_transfers = false;
                err = b43_dma_init(dev);
        }
        if (err)
@@@ -4733,7 -4752,7 +4752,7 @@@ static int b43_op_add_interface(struct 
        b43dbg(wl, "Adding Interface type %d\n", vif->type);
  
        dev = wl->current_dev;
 -      wl->operating = 1;
 +      wl->operating = true;
        wl->vif = vif;
        wl->if_type = vif->type;
        memcpy(wl->mac_addr, vif->addr, ETH_ALEN);
@@@ -4767,7 -4786,7 +4786,7 @@@ static void b43_op_remove_interface(str
        B43_WARN_ON(wl->vif != vif);
        wl->vif = NULL;
  
 -      wl->operating = 0;
 +      wl->operating = false;
  
        b43_adjust_opmode(dev);
        memset(wl->mac_addr, 0, ETH_ALEN);
@@@ -4789,12 -4808,12 +4808,12 @@@ static int b43_op_start(struct ieee8021
        memset(wl->bssid, 0, ETH_ALEN);
        memset(wl->mac_addr, 0, ETH_ALEN);
        wl->filter_flags = 0;
 -      wl->radiotap_enabled = 0;
 +      wl->radiotap_enabled = false;
        b43_qos_clear(wl);
 -      wl->beacon0_uploaded = 0;
 -      wl->beacon1_uploaded = 0;
 -      wl->beacon_templates_virgin = 1;
 -      wl->radio_enabled = 1;
 +      wl->beacon0_uploaded = false;
 +      wl->beacon1_uploaded = false;
 +      wl->beacon_templates_virgin = true;
 +      wl->radio_enabled = true;
  
        mutex_lock(&wl->mutex);
  
@@@ -4840,7 -4859,7 +4859,7 @@@ static void b43_op_stop(struct ieee8021
                        goto out_unlock;
        }
        b43_wireless_core_exit(dev);
 -      wl->radio_enabled = 0;
 +      wl->radio_enabled = false;
  
  out_unlock:
        mutex_unlock(&wl->mutex);
@@@ -5028,7 -5047,7 +5047,7 @@@ static int b43_wireless_core_attach(str
        struct pci_dev *pdev = NULL;
        int err;
        u32 tmp;
 -      bool have_2ghz_phy = 0, have_5ghz_phy = 0;
 +      bool have_2ghz_phy = false, have_5ghz_phy = false;
  
        /* Do NOT do any device initialization here.
         * Do it in wireless_core_init() instead.
        }
  
        dev->phy.gmode = have_2ghz_phy;
 -      dev->phy.radio_on = 1;
 +      dev->phy.radio_on = true;
        b43_wireless_core_reset(dev, dev->phy.gmode);
  
        err = b43_phy_versioning(dev);
            (pdev->device != 0x4312 &&
             pdev->device != 0x4319 && pdev->device != 0x4324)) {
                /* No multiband support. */
 -              have_2ghz_phy = 0;
 -              have_5ghz_phy = 0;
 +              have_2ghz_phy = false;
 +              have_5ghz_phy = false;
                switch (dev->phy.type) {
                case B43_PHYTYPE_A:
 -                      have_5ghz_phy = 1;
 +                      have_5ghz_phy = true;
                        break;
                case B43_PHYTYPE_LP: //FIXME not always!
  #if 0 //FIXME enabling 5GHz causes a NULL pointer dereference
                case B43_PHYTYPE_N:
                case B43_PHYTYPE_HT:
                case B43_PHYTYPE_LCN:
 -                      have_2ghz_phy = 1;
 +                      have_2ghz_phy = true;
                        break;
                default:
                        B43_WARN_ON(1);
                /* FIXME: For now we disable the A-PHY on multi-PHY devices. */
                if (dev->phy.type != B43_PHYTYPE_N &&
                    dev->phy.type != B43_PHYTYPE_LP) {
 -                      have_2ghz_phy = 1;
 -                      have_5ghz_phy = 0;
 +                      have_2ghz_phy = true;
 +                      have_5ghz_phy = false;
                }
        }
  
@@@ -5245,6 -5264,7 +5264,7 @@@ static struct b43_wl *b43_wireless_init
        struct ieee80211_hw *hw;
        struct b43_wl *wl;
        char chip_name[6];
+       int queue_num;
  
        hw = ieee80211_alloc_hw(sizeof(*wl), &b43_hw_ops);
        if (!hw) {
                BIT(NL80211_IFTYPE_WDS) |
                BIT(NL80211_IFTYPE_ADHOC);
  
-       hw->queues = modparam_qos ? 4 : 1;
+       hw->queues = modparam_qos ? B43_QOS_QUEUE_NUM : 1;
        wl->mac80211_initially_registered_queues = hw->queues;
        hw->max_rates = 2;
        SET_IEEE80211_DEV(hw, dev->dev);
        INIT_WORK(&wl->beacon_update_trigger, b43_beacon_update_trigger_work);
        INIT_WORK(&wl->txpower_adjust_work, b43_phy_txpower_adjust_work);
        INIT_WORK(&wl->tx_work, b43_tx_work);
-       skb_queue_head_init(&wl->tx_queue);
+       /* Initialize queues and flags. */
+       for (queue_num = 0; queue_num < B43_QOS_QUEUE_NUM; queue_num++) {
+               skb_queue_head_init(&wl->tx_queue[queue_num]);
+               wl->tx_queue_stopped[queue_num] = 0;
+       }
  
        snprintf(chip_name, ARRAY_SIZE(chip_name),
                 (dev->chip_id > 0x9999) ? "%d" : "%04X", dev->chip_id);
index f1a7e5890adca07cb06f6177798b09009887b9d4,e89b04bcd1f4ccdce31c1c288f0b1752e902fa87..0d25fe4069bf3aa48432678df9b97b0d84633d25
@@@ -78,19 -78,6 +78,6 @@@ enum b43_nphy_rssi_type 
        B43_NPHY_RSSI_TBD,
  };
  
- /* TODO: reorder functions */
- static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev,
-                                               bool enable);
- static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
-                                       u8 *events, u8 *delays, u8 length);
- static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
-                                      enum b43_nphy_rf_sequence seq);
- static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
-                                               u16 value, u8 core, bool off);
- static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
-                                               u16 value, u8 core);
- static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev);
  static inline bool b43_nphy_ipa(struct b43_wldev *dev)
  {
        enum ieee80211_band band = b43_current_band(dev->wl);
                (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ));
  }
  
- void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
- {//TODO
- }
- static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
- {//TODO
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */
+ static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev)
+ {
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+               if (dev->phy.rev >= 6) {
+                       if (dev->dev->chip_id == 47162)
+                               return txpwrctrl_tx_gain_ipa_rev5;
+                       return txpwrctrl_tx_gain_ipa_rev6;
+               } else if (dev->phy.rev >= 5) {
+                       return txpwrctrl_tx_gain_ipa_rev5;
+               } else {
+                       return txpwrctrl_tx_gain_ipa;
+               }
+       } else {
+               return txpwrctrl_tx_gain_ipa_5g;
+       }
  }
  
- static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
-                                                       bool ignore_tssi)
- {//TODO
-       return B43_TXPWR_RES_DONE;
- }
+ /**************************************************
+  * RF (just without b43_nphy_rf_control_intc_override)
+  **************************************************/
  
- static void b43_chantab_radio_upload(struct b43_wldev *dev,
-                               const struct b43_nphy_channeltab_entry_rev2 *e)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */
+ static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
+                                      enum b43_nphy_rf_sequence seq)
  {
-       b43_radio_write(dev, B2055_PLL_REF, e->radio_pll_ref);
-       b43_radio_write(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
-       b43_radio_write(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
-       b43_radio_write(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
-       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+       static const u16 trigger[] = {
+               [B43_RFSEQ_RX2TX]               = B43_NPHY_RFSEQTR_RX2TX,
+               [B43_RFSEQ_TX2RX]               = B43_NPHY_RFSEQTR_TX2RX,
+               [B43_RFSEQ_RESET2RX]            = B43_NPHY_RFSEQTR_RST2RX,
+               [B43_RFSEQ_UPDATE_GAINH]        = B43_NPHY_RFSEQTR_UPGH,
+               [B43_RFSEQ_UPDATE_GAINL]        = B43_NPHY_RFSEQTR_UPGL,
+               [B43_RFSEQ_UPDATE_GAINU]        = B43_NPHY_RFSEQTR_UPGU,
+       };
+       int i;
+       u16 seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
  
-       b43_radio_write(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
-       b43_radio_write(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
-       b43_radio_write(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
-       b43_radio_write(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
-       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+       B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
  
-       b43_radio_write(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
-       b43_radio_write(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
-       b43_radio_write(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
-       b43_radio_write(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
-       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+       b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+                   B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
+       b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
+       for (i = 0; i < 200; i++) {
+               if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
+                       goto ok;
+               msleep(1);
+       }
+       b43err(dev->wl, "RF sequence status timeout\n");
+ ok:
+       b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
+ }
  
-       b43_radio_write(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
-       b43_radio_write(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
-       b43_radio_write(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
-       b43_radio_write(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
-       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
+ static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
+                                               u16 value, u8 core, bool off)
+ {
+       int i;
+       u8 index = fls(field);
+       u8 addr, en_addr, val_addr;
+       /* we expect only one bit set */
+       B43_WARN_ON(field & (~(1 << (index - 1))));
  
-       b43_radio_write(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
-       b43_radio_write(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
-       b43_radio_write(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
-       b43_radio_write(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
-       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+       if (dev->phy.rev >= 3) {
+               const struct nphy_rf_control_override_rev3 *rf_ctrl;
+               for (i = 0; i < 2; i++) {
+                       if (index == 0 || index == 16) {
+                               b43err(dev->wl,
+                                       "Unsupported RF Ctrl Override call\n");
+                               return;
+                       }
  
-       b43_radio_write(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
-       b43_radio_write(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
- }
+                       rf_ctrl = &tbl_rf_control_override_rev3[index - 1];
+                       en_addr = B43_PHY_N((i == 0) ?
+                               rf_ctrl->en_addr0 : rf_ctrl->en_addr1);
+                       val_addr = B43_PHY_N((i == 0) ?
+                               rf_ctrl->val_addr0 : rf_ctrl->val_addr1);
  
- static void b43_chantab_radio_2056_upload(struct b43_wldev *dev,
-                               const struct b43_nphy_channeltab_entry_rev3 *e)
- {
-       b43_radio_write(dev, B2056_SYN_PLL_VCOCAL1, e->radio_syn_pll_vcocal1);
-       b43_radio_write(dev, B2056_SYN_PLL_VCOCAL2, e->radio_syn_pll_vcocal2);
-       b43_radio_write(dev, B2056_SYN_PLL_REFDIV, e->radio_syn_pll_refdiv);
-       b43_radio_write(dev, B2056_SYN_PLL_MMD2, e->radio_syn_pll_mmd2);
-       b43_radio_write(dev, B2056_SYN_PLL_MMD1, e->radio_syn_pll_mmd1);
-       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1,
-                                       e->radio_syn_pll_loopfilter1);
-       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2,
-                                       e->radio_syn_pll_loopfilter2);
-       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER3,
-                                       e->radio_syn_pll_loopfilter3);
-       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4,
-                                       e->radio_syn_pll_loopfilter4);
-       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER5,
-                                       e->radio_syn_pll_loopfilter5);
-       b43_radio_write(dev, B2056_SYN_RESERVED_ADDR27,
-                                       e->radio_syn_reserved_addr27);
-       b43_radio_write(dev, B2056_SYN_RESERVED_ADDR28,
-                                       e->radio_syn_reserved_addr28);
-       b43_radio_write(dev, B2056_SYN_RESERVED_ADDR29,
-                                       e->radio_syn_reserved_addr29);
-       b43_radio_write(dev, B2056_SYN_LOGEN_VCOBUF1,
-                                       e->radio_syn_logen_vcobuf1);
-       b43_radio_write(dev, B2056_SYN_LOGEN_MIXER2, e->radio_syn_logen_mixer2);
-       b43_radio_write(dev, B2056_SYN_LOGEN_BUF3, e->radio_syn_logen_buf3);
-       b43_radio_write(dev, B2056_SYN_LOGEN_BUF4, e->radio_syn_logen_buf4);
+                       if (off) {
+                               b43_phy_mask(dev, en_addr, ~(field));
+                               b43_phy_mask(dev, val_addr,
+                                               ~(rf_ctrl->val_mask));
+                       } else {
+                               if (core == 0 || ((1 << core) & i) != 0) {
+                                       b43_phy_set(dev, en_addr, field);
+                                       b43_phy_maskset(dev, val_addr,
+                                               ~(rf_ctrl->val_mask),
+                                               (value << rf_ctrl->val_shift));
+                               }
+                       }
+               }
+       } else {
+               const struct nphy_rf_control_override_rev2 *rf_ctrl;
+               if (off) {
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~(field));
+                       value = 0;
+               } else {
+                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER, field);
+               }
  
-       b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAA_TUNE,
-                                       e->radio_rx0_lnaa_tune);
-       b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAG_TUNE,
-                                       e->radio_rx0_lnag_tune);
+               for (i = 0; i < 2; i++) {
+                       if (index <= 1 || index == 16) {
+                               b43err(dev->wl,
+                                       "Unsupported RF Ctrl Override call\n");
+                               return;
+                       }
  
-       b43_radio_write(dev, B2056_TX0 | B2056_TX_INTPAA_BOOST_TUNE,
-                                       e->radio_tx0_intpaa_boost_tune);
-       b43_radio_write(dev, B2056_TX0 | B2056_TX_INTPAG_BOOST_TUNE,
-                                       e->radio_tx0_intpag_boost_tune);
-       b43_radio_write(dev, B2056_TX0 | B2056_TX_PADA_BOOST_TUNE,
-                                       e->radio_tx0_pada_boost_tune);
-       b43_radio_write(dev, B2056_TX0 | B2056_TX_PADG_BOOST_TUNE,
-                                       e->radio_tx0_padg_boost_tune);
-       b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAA_BOOST_TUNE,
-                                       e->radio_tx0_pgaa_boost_tune);
-       b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAG_BOOST_TUNE,
-                                       e->radio_tx0_pgag_boost_tune);
-       b43_radio_write(dev, B2056_TX0 | B2056_TX_MIXA_BOOST_TUNE,
-                                       e->radio_tx0_mixa_boost_tune);
-       b43_radio_write(dev, B2056_TX0 | B2056_TX_MIXG_BOOST_TUNE,
-                                       e->radio_tx0_mixg_boost_tune);
+                       if (index == 2 || index == 10 ||
+                           (index >= 13 && index <= 15)) {
+                               core = 1;
+                       }
  
-       b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAA_TUNE,
-                                       e->radio_rx1_lnaa_tune);
-       b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAG_TUNE,
-                                       e->radio_rx1_lnag_tune);
+                       rf_ctrl = &tbl_rf_control_override_rev2[index - 2];
+                       addr = B43_PHY_N((i == 0) ?
+                               rf_ctrl->addr0 : rf_ctrl->addr1);
  
-       b43_radio_write(dev, B2056_TX1 | B2056_TX_INTPAA_BOOST_TUNE,
-                                       e->radio_tx1_intpaa_boost_tune);
-       b43_radio_write(dev, B2056_TX1 | B2056_TX_INTPAG_BOOST_TUNE,
-                                       e->radio_tx1_intpag_boost_tune);
-       b43_radio_write(dev, B2056_TX1 | B2056_TX_PADA_BOOST_TUNE,
-                                       e->radio_tx1_pada_boost_tune);
-       b43_radio_write(dev, B2056_TX1 | B2056_TX_PADG_BOOST_TUNE,
-                                       e->radio_tx1_padg_boost_tune);
-       b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAA_BOOST_TUNE,
-                                       e->radio_tx1_pgaa_boost_tune);
-       b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAG_BOOST_TUNE,
-                                       e->radio_tx1_pgag_boost_tune);
-       b43_radio_write(dev, B2056_TX1 | B2056_TX_MIXA_BOOST_TUNE,
-                                       e->radio_tx1_mixa_boost_tune);
-       b43_radio_write(dev, B2056_TX1 | B2056_TX_MIXG_BOOST_TUNE,
-                                       e->radio_tx1_mixg_boost_tune);
+                       if ((core & (1 << i)) != 0)
+                               b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask),
+                                               (value << rf_ctrl->shift));
+                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1);
+                       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                                       B43_NPHY_RFCTL_CMD_START);
+                       udelay(1);
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, 0xFFFE);
+               }
+       }
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2056Setup */
- static void b43_radio_2056_setup(struct b43_wldev *dev,
-                               const struct b43_nphy_channeltab_entry_rev3 *e)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */
+ static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
+                                               u16 value, u8 core)
  {
-       struct ssb_sprom *sprom = dev->dev->bus_sprom;
-       enum ieee80211_band band = b43_current_band(dev->wl);
-       u16 offset;
-       u8 i;
-       u16 bias, cbias, pag_boost, pgag_boost, mixg_boost, padg_boost;
+       u8 i, j;
+       u16 reg, tmp, val;
  
        B43_WARN_ON(dev->phy.rev < 3);
+       B43_WARN_ON(field > 4);
  
-       b43_chantab_radio_2056_upload(dev, e);
-       b2056_upload_syn_pll_cp2(dev, band == IEEE80211_BAND_5GHZ);
+       for (i = 0; i < 2; i++) {
+               if ((core == 1 && i == 1) || (core == 2 && !i))
+                       continue;
  
-       if (sprom->boardflags2_lo & B43_BFL2_GPLL_WAR &&
-           b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F);
-               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1F);
-               if (dev->dev->chip_id == 0x4716) {
-                       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x14);
-                       b43_radio_write(dev, B2056_SYN_PLL_CP2, 0);
-               } else {
-                       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x0B);
-                       b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x14);
-               }
-       }
-       if (sprom->boardflags2_lo & B43_BFL2_APLL_WAR &&
-           b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
-               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F);
-               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1F);
-               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x05);
-               b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x0C);
-       }
-       if (dev->phy.n->ipa2g_on && band == IEEE80211_BAND_2GHZ) {
-               for (i = 0; i < 2; i++) {
-                       offset = i ? B2056_TX1 : B2056_TX0;
-                       if (dev->phy.rev >= 5) {
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_PADG_IDAC, 0xcc);
+               reg = (i == 0) ?
+                       B43_NPHY_RFCTL_INTC1 : B43_NPHY_RFCTL_INTC2;
+               b43_phy_mask(dev, reg, 0xFBFF);
  
-                               if (dev->dev->chip_id == 0x4716) {
-                                       bias = 0x40;
-                                       cbias = 0x45;
-                                       pag_boost = 0x5;
-                                       pgag_boost = 0x33;
-                                       mixg_boost = 0x55;
-                               } else {
-                                       bias = 0x25;
-                                       cbias = 0x20;
-                                       pag_boost = 0x4;
-                                       pgag_boost = 0x03;
-                                       mixg_boost = 0x65;
+               switch (field) {
+               case 0:
+                       b43_phy_write(dev, reg, 0);
+                       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+                       break;
+               case 1:
+                       if (!i) {
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC1,
+                                               0xFC3F, (value << 6));
+                               b43_phy_maskset(dev, B43_NPHY_TXF_40CO_B1S1,
+                                               0xFFFE, 1);
+                               b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                                               B43_NPHY_RFCTL_CMD_START);
+                               for (j = 0; j < 100; j++) {
+                                       if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_START) {
+                                               j = 0;
+                                               break;
+                                       }
+                                       udelay(10);
                                }
-                               padg_boost = 0x77;
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_INTPAG_IMAIN_STAT,
-                                       bias);
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_INTPAG_IAUX_STAT,
-                                       bias);
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_INTPAG_CASCBIAS,
-                                       cbias);
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_INTPAG_BOOST_TUNE,
-                                       pag_boost);
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_PGAG_BOOST_TUNE,
-                                       pgag_boost);
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_PADG_BOOST_TUNE,
-                                       padg_boost);
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_MIXG_BOOST_TUNE,
-                                       mixg_boost);
+                               if (j)
+                                       b43err(dev->wl,
+                                               "intc override timeout\n");
+                               b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S1,
+                                               0xFFFE);
                        } else {
-                               bias = dev->phy.is_40mhz ? 0x40 : 0x20;
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_INTPAG_IMAIN_STAT,
-                                       bias);
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_INTPAG_IAUX_STAT,
-                                       bias);
-                               b43_radio_write(dev,
-                                       offset | B2056_TX_INTPAG_CASCBIAS,
-                                       0x30);
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC2,
+                                               0xFC3F, (value << 6));
+                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
+                                               0xFFFE, 1);
+                               b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                                               B43_NPHY_RFCTL_CMD_RXTX);
+                               for (j = 0; j < 100; j++) {
+                                       if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_RXTX) {
+                                               j = 0;
+                                               break;
+                                       }
+                                       udelay(10);
+                               }
+                               if (j)
+                                       b43err(dev->wl,
+                                               "intc override timeout\n");
+                               b43_phy_mask(dev, B43_NPHY_RFCTL_OVER,
+                                               0xFFFE);
                        }
-                       b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee);
+                       break;
+               case 2:
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+                               tmp = 0x0020;
+                               val = value << 5;
+                       } else {
+                               tmp = 0x0010;
+                               val = value << 4;
+                       }
+                       b43_phy_maskset(dev, reg, ~tmp, val);
+                       break;
+               case 3:
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+                               tmp = 0x0001;
+                               val = value;
+                       } else {
+                               tmp = 0x0004;
+                               val = value << 2;
+                       }
+                       b43_phy_maskset(dev, reg, ~tmp, val);
+                       break;
+               case 4:
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+                               tmp = 0x0002;
+                               val = value << 1;
+                       } else {
+                               tmp = 0x0008;
+                               val = value << 3;
+                       }
+                       b43_phy_maskset(dev, reg, ~tmp, val);
+                       break;
                }
-       } else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) {
-               /* TODO */
        }
+ }
  
-       udelay(50);
-       /* VCO calibration */
-       b43_radio_write(dev, B2056_SYN_PLL_VCOCAL12, 0x00);
-       b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x38);
-       b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x18);
-       b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x38);
-       b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x39);
-       udelay(300);
+ /**************************************************
+  * Various PHY ops
+  **************************************************/
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
+ static void b43_nphy_write_clip_detection(struct b43_wldev *dev,
+                                         const u16 *clip_st)
+ {
+       b43_phy_write(dev, B43_NPHY_C1_CLIP1THRES, clip_st[0]);
+       b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]);
  }
  
- static void b43_chantab_phy_upload(struct b43_wldev *dev,
                                 const struct b43_phy_n_sfo_cfg *e)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
  {
-       b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
-       b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
-       b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3);
-       b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4);
-       b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5);
-       b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
+       clip_st[0] = b43_phy_read(dev, B43_NPHY_C1_CLIP1THRES);
+       clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
- static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */
+ static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
  {
-       struct b43_phy_n *nphy = dev->phy.n;
-       u8 i;
-       u16 bmask, val, tmp;
-       enum ieee80211_band band = b43_current_band(dev->wl);
+       u16 tmp;
  
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 1);
+       if (dev->dev->core_rev == 16)
+               b43_mac_suspend(dev);
  
-       nphy->txpwrctrl = enable;
-       if (!enable) {
-               if (dev->phy.rev >= 3 &&
-                   (b43_phy_read(dev, B43_NPHY_TXPCTL_CMD) &
-                    (B43_NPHY_TXPCTL_CMD_COEFF |
-                     B43_NPHY_TXPCTL_CMD_HWPCTLEN |
-                     B43_NPHY_TXPCTL_CMD_PCTLEN))) {
-                       /* We disable enabled TX pwr ctl, save it's state */
-                       nphy->tx_pwr_idx[0] = b43_phy_read(dev,
-                                               B43_NPHY_C1_TXPCTL_STAT) & 0x7f;
-                       nphy->tx_pwr_idx[1] = b43_phy_read(dev,
-                                               B43_NPHY_C2_TXPCTL_STAT) & 0x7f;
-               }
+       tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL);
+       tmp &= (B43_NPHY_CLASSCTL_CCKEN | B43_NPHY_CLASSCTL_OFDMEN |
+               B43_NPHY_CLASSCTL_WAITEDEN);
+       tmp &= ~mask;
+       tmp |= (val & mask);
+       b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp);
  
-               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6840);
-               for (i = 0; i < 84; i++)
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0);
+       if (dev->dev->core_rev == 16)
+               b43_mac_enable(dev);
  
-               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6C40);
-               for (i = 0; i < 84; i++)
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0);
+       return tmp;
+ }
  
-               tmp = B43_NPHY_TXPCTL_CMD_COEFF | B43_NPHY_TXPCTL_CMD_HWPCTLEN;
              if (dev->phy.rev >= 3)
-                       tmp |= B43_NPHY_TXPCTL_CMD_PCTLEN;
-               b43_phy_mask(dev, B43_NPHY_TXPCTL_CMD, ~tmp);
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
static void b43_nphy_reset_cca(struct b43_wldev *dev)
+ {
+       u16 bbcfg;
  
-               if (dev->phy.rev >= 3) {
-                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0100);
-                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0100);
-               } else {
-                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4000);
-               }
+       b43_phy_force_clock(dev, 1);
+       bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
+       b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA);
+       udelay(1);
+       b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
+       b43_phy_force_clock(dev, 0);
+       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+ }
  
-               if (dev->phy.rev == 2)
-                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
-                               ~B43_NPHY_BPHY_CTL3_SCALE, 0x53);
-               else if (dev->phy.rev < 2)
-                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
-                               ~B43_NPHY_BPHY_CTL3_SCALE, 0x5A);
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */
+ static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable)
+ {
+       struct b43_phy *phy = &dev->phy;
+       struct b43_phy_n *nphy = phy->n;
  
-               if (dev->phy.rev < 2 && dev->phy.is_40mhz)
-                       b43_hf_write(dev, b43_hf_read(dev) | B43_HF_TSSIRPSMW);
+       if (enable) {
+               static const u16 clip[] = { 0xFFFF, 0xFFFF };
+               if (nphy->deaf_count++ == 0) {
+                       nphy->classifier_state = b43_nphy_classifier(dev, 0, 0);
+                       b43_nphy_classifier(dev, 0x7, 0);
+                       b43_nphy_read_clip_detection(dev, nphy->clip_state);
+                       b43_nphy_write_clip_detection(dev, clip);
+               }
+               b43_nphy_reset_cca(dev);
        } else {
-               b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84,
-                                   nphy->adj_pwr_tbl);
-               b43_ntab_write_bulk(dev, B43_NTAB16(27, 64), 84,
-                                   nphy->adj_pwr_tbl);
-               bmask = B43_NPHY_TXPCTL_CMD_COEFF |
-                       B43_NPHY_TXPCTL_CMD_HWPCTLEN;
-               /* wl does useless check for "enable" param here */
-               val = B43_NPHY_TXPCTL_CMD_COEFF | B43_NPHY_TXPCTL_CMD_HWPCTLEN;
-               if (dev->phy.rev >= 3) {
-                       bmask |= B43_NPHY_TXPCTL_CMD_PCTLEN;
-                       if (val)
-                               val |= B43_NPHY_TXPCTL_CMD_PCTLEN;
-               }
-               b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, ~(bmask), val);
-               if (band == IEEE80211_BAND_5GHZ) {
-                       b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
-                                       ~B43_NPHY_TXPCTL_CMD_INIT, 0x64);
-                       if (dev->phy.rev > 1)
-                               b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT,
-                                               ~B43_NPHY_TXPCTL_INIT_PIDXI1,
-                                               0x64);
-               }
-               if (dev->phy.rev >= 3) {
-                       if (nphy->tx_pwr_idx[0] != 128 &&
-                           nphy->tx_pwr_idx[1] != 128) {
-                               /* Recover TX pwr ctl state */
-                               b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
-                                               ~B43_NPHY_TXPCTL_CMD_INIT,
-                                               nphy->tx_pwr_idx[0]);
-                               if (dev->phy.rev > 1)
-                                       b43_phy_maskset(dev,
-                                               B43_NPHY_TXPCTL_INIT,
-                                               ~0xff, nphy->tx_pwr_idx[1]);
-                       }
-               }
-               if (dev->phy.rev >= 3) {
-                       b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x100);
-                       b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x100);
-               } else {
-                       b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x4000);
-               }
-               if (dev->phy.rev == 2)
-                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x3b);
-               else if (dev->phy.rev < 2)
-                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x40);
-               if (dev->phy.rev < 2 && dev->phy.is_40mhz)
-                       b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_TSSIRPSMW);
-               if (b43_nphy_ipa(dev)) {
-                       b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x4);
-                       b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x4);
+               if (--nphy->deaf_count == 0) {
+                       b43_nphy_classifier(dev, 0x7, nphy->classifier_state);
+                       b43_nphy_write_clip_detection(dev, nphy->clip_state);
                }
        }
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */
- static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */
+ static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
  {
        struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = dev->dev->bus_sprom;
  
-       u8 txpi[2], bbmult, i;
-       u16 tmp, radio_gain, dac_gain;
-       u16 freq = dev->phy.channel_freq;
-       u32 txgain;
-       /* u32 gaintbl; rev3+ */
+       u8 i;
+       s16 tmp;
+       u16 data[4];
+       s16 gain[2];
+       u16 minmax[2];
+       static const u16 lna_gain[4] = { -2, 10, 19, 25 };
  
        if (nphy->hang_avoid)
                b43_nphy_stay_in_carrier_search(dev, 1);
  
-       if (dev->phy.rev >= 7) {
-               txpi[0] = txpi[1] = 30;
-       } else if (dev->phy.rev >= 3) {
-               txpi[0] = 40;
-               txpi[1] = 40;
-       } else if (sprom->revision < 4) {
-               txpi[0] = 72;
-               txpi[1] = 72;
-       } else {
+       if (nphy->gain_boost) {
                if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-                       txpi[0] = sprom->txpid2g[0];
-                       txpi[1] = sprom->txpid2g[1];
-               } else if (freq >= 4900 && freq < 5100) {
-                       txpi[0] = sprom->txpid5gl[0];
-                       txpi[1] = sprom->txpid5gl[1];
-               } else if (freq >= 5100 && freq < 5500) {
-                       txpi[0] = sprom->txpid5g[0];
-                       txpi[1] = sprom->txpid5g[1];
-               } else if (freq >= 5500) {
-                       txpi[0] = sprom->txpid5gh[0];
-                       txpi[1] = sprom->txpid5gh[1];
+                       gain[0] = 6;
+                       gain[1] = 6;
                } else {
-                       txpi[0] = 91;
-                       txpi[1] = 91;
+                       tmp = 40370 - 315 * dev->phy.channel;
+                       gain[0] = ((tmp >> 13) + ((tmp >> 12) & 1));
+                       tmp = 23242 - 224 * dev->phy.channel;
+                       gain[1] = ((tmp >> 13) + ((tmp >> 12) & 1));
                }
+       } else {
+               gain[0] = 0;
+               gain[1] = 0;
        }
-       if (dev->phy.rev < 7 &&
-           (txpi[0] < 40 || txpi[0] > 100 || txpi[1] < 40 || txpi[1] > 10))
-               txpi[0] = txpi[1] = 91;
-       /*
-       for (i = 0; i < 2; i++) {
-               nphy->txpwrindex[i].index_internal = txpi[i];
-               nphy->txpwrindex[i].index_internal_save = txpi[i];
-       }
-       */
  
        for (i = 0; i < 2; i++) {
-               if (dev->phy.rev >= 3) {
-                       if (b43_nphy_ipa(dev)) {
-                               txgain = *(b43_nphy_get_ipa_gain_table(dev) +
-                                               txpi[i]);
-                       } else if (b43_current_band(dev->wl) ==
-                                  IEEE80211_BAND_5GHZ) {
-                               /* FIXME: use 5GHz tables */
-                               txgain =
-                                       b43_ntab_tx_gain_rev3plus_2ghz[txpi[i]];
-                       } else {
-                               if (dev->phy.rev >= 5 &&
-                                   sprom->fem.ghz5.extpa_gain == 3)
-                                       ; /* FIXME: 5GHz_txgain_HiPwrEPA */
-                               txgain =
-                                       b43_ntab_tx_gain_rev3plus_2ghz[txpi[i]];
-                       }
-                       radio_gain = (txgain >> 16) & 0x1FFFF;
-               } else {
-                       txgain = b43_ntab_tx_gain_rev0_1_2[txpi[i]];
-                       radio_gain = (txgain >> 16) & 0x1FFF;
-               }
-               if (dev->phy.rev >= 7)
-                       dac_gain = (txgain >> 8) & 0x7;
-               else
-                       dac_gain = (txgain >> 8) & 0x3F;
-               bbmult = txgain & 0xFF;
-               if (dev->phy.rev >= 3) {
-                       if (i == 0)
-                               b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0100);
-                       else
-                               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0100);
+               if (nphy->elna_gain_config) {
+                       data[0] = 19 + gain[i];
+                       data[1] = 25 + gain[i];
+                       data[2] = 25 + gain[i];
+                       data[3] = 25 + gain[i];
                } else {
-                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4000);
+                       data[0] = lna_gain[0] + gain[i];
+                       data[1] = lna_gain[1] + gain[i];
+                       data[2] = lna_gain[2] + gain[i];
+                       data[3] = lna_gain[3] + gain[i];
                }
+               b43_ntab_write_bulk(dev, B43_NTAB16(i, 8), 4, data);
  
-               if (i == 0)
-                       b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN1, dac_gain);
-               else
-                       b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN2, dac_gain);
-               b43_ntab_write(dev, B43_NTAB16(0x7, 0x110 + i), radio_gain);
-               tmp = b43_ntab_read(dev, B43_NTAB16(0xF, 0x57));
-               if (i == 0)
-                       tmp = (tmp & 0x00FF) | (bbmult << 8);
-               else
-                       tmp = (tmp & 0xFF00) | bbmult;
-               b43_ntab_write(dev, B43_NTAB16(0xF, 0x57), tmp);
-               if (b43_nphy_ipa(dev)) {
-                       u32 tmp32;
-                       u16 reg = (i == 0) ?
-                               B43_NPHY_PAPD_EN0 : B43_NPHY_PAPD_EN1;
-                       tmp32 = b43_ntab_read(dev, B43_NTAB32(26 + i,
-                                                             576 + txpi[i]));
-                       b43_phy_maskset(dev, reg, 0xE00F, (u32) tmp32 << 4);
-                       b43_phy_set(dev, reg, 0x4);
-               }
+               minmax[i] = 23 + gain[i];
        }
  
-       b43_phy_mask(dev, B43_NPHY_BPHY_CTL2, ~B43_NPHY_BPHY_CTL2_LUT);
+       b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, ~B43_NPHY_C1_MINGAIN,
+                               minmax[0] << B43_NPHY_C1_MINGAIN_SHIFT);
+       b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, ~B43_NPHY_C2_MINGAIN,
+                               minmax[1] << B43_NPHY_C2_MINGAIN_SHIFT);
  
        if (nphy->hang_avoid)
                b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
- static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */
+ static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
+                                       u8 *events, u8 *delays, u8 length)
  {
-       struct b43_phy *phy = &dev->phy;
-       const u32 *table = NULL;
- #if 0
-       TODO: b43_ntab_papd_pga_gain_delta_ipa_2*
-       u32 rfpwr_offset;
-       u8 pga_gain;
-       int i;
- #endif
+       struct b43_phy_n *nphy = dev->phy.n;
+       u8 i;
+       u8 end = (dev->phy.rev >= 3) ? 0x1F : 0x0F;
+       u16 offset1 = cmd << 4;
+       u16 offset2 = offset1 + 0x80;
  
-       if (phy->rev >= 3) {
-               if (b43_nphy_ipa(dev)) {
-                       table = b43_nphy_get_ipa_gain_table(dev);
-               } else {
-                       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
-                               if (phy->rev == 3)
-                                       table = b43_ntab_tx_gain_rev3_5ghz;
-                               if (phy->rev == 4)
-                                       table = b43_ntab_tx_gain_rev4_5ghz;
-                               else
-                                       table = b43_ntab_tx_gain_rev5plus_5ghz;
-                       } else {
-                               table = b43_ntab_tx_gain_rev3plus_2ghz;
-                       }
-               }
-       } else {
-               table = b43_ntab_tx_gain_rev0_1_2;
-       }
-       b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, table);
-       b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, table);
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, true);
  
-       if (phy->rev >= 3) {
- #if 0
-               nphy->gmval = (table[0] >> 16) & 0x7000;
+       b43_ntab_write_bulk(dev, B43_NTAB8(7, offset1), length, events);
+       b43_ntab_write_bulk(dev, B43_NTAB8(7, offset2), length, delays);
  
-               for (i = 0; i < 128; i++) {
-                       pga_gain = (table[i] >> 24) & 0xF;
-                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
-                               rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_2g[pga_gain];
-                       else
-                               rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_5g[pga_gain];
-                       b43_ntab_write(dev, B43_NTAB32(26, 576 + i),
-                                      rfpwr_offset);
-                       b43_ntab_write(dev, B43_NTAB32(27, 576 + i),
-                                      rfpwr_offset);
-               }
- #endif
+       for (i = length; i < 16; i++) {
+               b43_ntab_write(dev, B43_NTAB8(7, offset1 + i), end);
+               b43_ntab_write(dev, B43_NTAB8(7, offset2 + i), 1);
        }
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, false);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */
- static void b43_radio_2055_setup(struct b43_wldev *dev,
-                               const struct b43_nphy_channeltab_entry_rev2 *e)
- {
-       B43_WARN_ON(dev->phy.rev >= 3);
-       b43_chantab_radio_upload(dev, e);
-       udelay(50);
-       b43_radio_write(dev, B2055_VCO_CAL10, 0x05);
-       b43_radio_write(dev, B2055_VCO_CAL10, 0x45);
-       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
-       b43_radio_write(dev, B2055_VCO_CAL10, 0x65);
-       udelay(300);
- }
+ /**************************************************
+  * Radio 0x2056
+  **************************************************/
  
- static void b43_radio_init2055_pre(struct b43_wldev *dev)
+ static void b43_chantab_radio_2056_upload(struct b43_wldev *dev,
+                               const struct b43_nphy_channeltab_entry_rev3 *e)
  {
-       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
-                    ~B43_NPHY_RFCTL_CMD_PORFORCE);
-       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
-                   B43_NPHY_RFCTL_CMD_CHIP0PU |
-                   B43_NPHY_RFCTL_CMD_OEPORFORCE);
-       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
-                   B43_NPHY_RFCTL_CMD_PORFORCE);
+       b43_radio_write(dev, B2056_SYN_PLL_VCOCAL1, e->radio_syn_pll_vcocal1);
+       b43_radio_write(dev, B2056_SYN_PLL_VCOCAL2, e->radio_syn_pll_vcocal2);
+       b43_radio_write(dev, B2056_SYN_PLL_REFDIV, e->radio_syn_pll_refdiv);
+       b43_radio_write(dev, B2056_SYN_PLL_MMD2, e->radio_syn_pll_mmd2);
+       b43_radio_write(dev, B2056_SYN_PLL_MMD1, e->radio_syn_pll_mmd1);
+       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1,
+                                       e->radio_syn_pll_loopfilter1);
+       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2,
+                                       e->radio_syn_pll_loopfilter2);
+       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER3,
+                                       e->radio_syn_pll_loopfilter3);
+       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4,
+                                       e->radio_syn_pll_loopfilter4);
+       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER5,
+                                       e->radio_syn_pll_loopfilter5);
+       b43_radio_write(dev, B2056_SYN_RESERVED_ADDR27,
+                                       e->radio_syn_reserved_addr27);
+       b43_radio_write(dev, B2056_SYN_RESERVED_ADDR28,
+                                       e->radio_syn_reserved_addr28);
+       b43_radio_write(dev, B2056_SYN_RESERVED_ADDR29,
+                                       e->radio_syn_reserved_addr29);
+       b43_radio_write(dev, B2056_SYN_LOGEN_VCOBUF1,
+                                       e->radio_syn_logen_vcobuf1);
+       b43_radio_write(dev, B2056_SYN_LOGEN_MIXER2, e->radio_syn_logen_mixer2);
+       b43_radio_write(dev, B2056_SYN_LOGEN_BUF3, e->radio_syn_logen_buf3);
+       b43_radio_write(dev, B2056_SYN_LOGEN_BUF4, e->radio_syn_logen_buf4);
+       b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAA_TUNE,
+                                       e->radio_rx0_lnaa_tune);
+       b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAG_TUNE,
+                                       e->radio_rx0_lnag_tune);
+       b43_radio_write(dev, B2056_TX0 | B2056_TX_INTPAA_BOOST_TUNE,
+                                       e->radio_tx0_intpaa_boost_tune);
+       b43_radio_write(dev, B2056_TX0 | B2056_TX_INTPAG_BOOST_TUNE,
+                                       e->radio_tx0_intpag_boost_tune);
+       b43_radio_write(dev, B2056_TX0 | B2056_TX_PADA_BOOST_TUNE,
+                                       e->radio_tx0_pada_boost_tune);
+       b43_radio_write(dev, B2056_TX0 | B2056_TX_PADG_BOOST_TUNE,
+                                       e->radio_tx0_padg_boost_tune);
+       b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAA_BOOST_TUNE,
+                                       e->radio_tx0_pgaa_boost_tune);
+       b43_radio_write(dev, B2056_TX0 | B2056_TX_PGAG_BOOST_TUNE,
+                                       e->radio_tx0_pgag_boost_tune);
+       b43_radio_write(dev, B2056_TX0 | B2056_TX_MIXA_BOOST_TUNE,
+                                       e->radio_tx0_mixa_boost_tune);
+       b43_radio_write(dev, B2056_TX0 | B2056_TX_MIXG_BOOST_TUNE,
+                                       e->radio_tx0_mixg_boost_tune);
+       b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAA_TUNE,
+                                       e->radio_rx1_lnaa_tune);
+       b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAG_TUNE,
+                                       e->radio_rx1_lnag_tune);
+       b43_radio_write(dev, B2056_TX1 | B2056_TX_INTPAA_BOOST_TUNE,
+                                       e->radio_tx1_intpaa_boost_tune);
+       b43_radio_write(dev, B2056_TX1 | B2056_TX_INTPAG_BOOST_TUNE,
+                                       e->radio_tx1_intpag_boost_tune);
+       b43_radio_write(dev, B2056_TX1 | B2056_TX_PADA_BOOST_TUNE,
+                                       e->radio_tx1_pada_boost_tune);
+       b43_radio_write(dev, B2056_TX1 | B2056_TX_PADG_BOOST_TUNE,
+                                       e->radio_tx1_padg_boost_tune);
+       b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAA_BOOST_TUNE,
+                                       e->radio_tx1_pgaa_boost_tune);
+       b43_radio_write(dev, B2056_TX1 | B2056_TX_PGAG_BOOST_TUNE,
+                                       e->radio_tx1_pgag_boost_tune);
+       b43_radio_write(dev, B2056_TX1 | B2056_TX_MIXA_BOOST_TUNE,
+                                       e->radio_tx1_mixa_boost_tune);
+       b43_radio_write(dev, B2056_TX1 | B2056_TX_MIXG_BOOST_TUNE,
+                                       e->radio_tx1_mixg_boost_tune);
  }
  
- static void b43_radio_init2055_post(struct b43_wldev *dev)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2056Setup */
+ static void b43_radio_2056_setup(struct b43_wldev *dev,
+                               const struct b43_nphy_channeltab_entry_rev3 *e)
  {
-       struct b43_phy_n *nphy = dev->phy.n;
        struct ssb_sprom *sprom = dev->dev->bus_sprom;
-       int i;
-       u16 val;
-       bool workaround = false;
+       enum ieee80211_band band = b43_current_band(dev->wl);
+       u16 offset;
+       u8 i;
+       u16 bias, cbias, pag_boost, pgag_boost, mixg_boost, padg_boost;
  
-       if (sprom->revision < 4)
-               workaround = (dev->dev->board_vendor != PCI_VENDOR_ID_BROADCOM
-                             && dev->dev->board_type == 0x46D
-                             && dev->dev->board_rev >= 0x41);
-       else
-               workaround =
-                       !(sprom->boardflags2_lo & B43_BFL2_RXBB_INT_REG_DIS);
+       B43_WARN_ON(dev->phy.rev < 3);
  
-       b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
-       if (workaround) {
-               b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
-               b43_radio_mask(dev, B2055_C2_RX_BB_REG, 0x7F);
-       }
-       b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0xFFC0, 0x2C);
-       b43_radio_write(dev, B2055_CAL_MISC, 0x3C);
-       b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE);
-       b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80);
-       b43_radio_set(dev, B2055_CAL_MISC, 0x1);
-       msleep(1);
-       b43_radio_set(dev, B2055_CAL_MISC, 0x40);
-       for (i = 0; i < 200; i++) {
-               val = b43_radio_read(dev, B2055_CAL_COUT2);
-               if (val & 0x80) {
-                       i = 0;
-                       break;
+       b43_chantab_radio_2056_upload(dev, e);
+       b2056_upload_syn_pll_cp2(dev, band == IEEE80211_BAND_5GHZ);
+       if (sprom->boardflags2_lo & B43_BFL2_GPLL_WAR &&
+           b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F);
+               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1F);
+               if (dev->dev->chip_id == 0x4716) {
+                       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x14);
+                       b43_radio_write(dev, B2056_SYN_PLL_CP2, 0);
+               } else {
+                       b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x0B);
+                       b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x14);
                }
-               udelay(10);
        }
-       if (i)
-               b43err(dev->wl, "radio post init timeout\n");
-       b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
-       b43_switch_channel(dev, dev->phy.channel);
-       b43_radio_write(dev, B2055_C1_RX_BB_LPF, 0x9);
-       b43_radio_write(dev, B2055_C2_RX_BB_LPF, 0x9);
-       b43_radio_write(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
-       b43_radio_write(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
-       b43_radio_maskset(dev, B2055_C1_LNA_GAINBST, 0xFFF8, 0x6);
-       b43_radio_maskset(dev, B2055_C2_LNA_GAINBST, 0xFFF8, 0x6);
-       if (!nphy->gain_boost) {
-               b43_radio_set(dev, B2055_C1_RX_RFSPC1, 0x2);
-               b43_radio_set(dev, B2055_C2_RX_RFSPC1, 0x2);
-       } else {
-               b43_radio_mask(dev, B2055_C1_RX_RFSPC1, 0xFFFD);
-               b43_radio_mask(dev, B2055_C2_RX_RFSPC1, 0xFFFD);
+       if (sprom->boardflags2_lo & B43_BFL2_APLL_WAR &&
+           b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
+               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER1, 0x1F);
+               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER2, 0x1F);
+               b43_radio_write(dev, B2056_SYN_PLL_LOOPFILTER4, 0x05);
+               b43_radio_write(dev, B2056_SYN_PLL_CP2, 0x0C);
        }
-       udelay(2);
- }
  
- /*
-  * Initialize a Broadcom 2055 N-radio
-  * http://bcm-v4.sipsolutions.net/802.11/Radio/2055/Init
-  */
- static void b43_radio_init2055(struct b43_wldev *dev)
- {
-       b43_radio_init2055_pre(dev);
-       if (b43_status(dev) < B43_STAT_INITIALIZED) {
-               /* Follow wl, not specs. Do not force uploading all regs */
-               b2055_upload_inittab(dev, 0, 0);
-       } else {
-               bool ghz5 = b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ;
-               b2055_upload_inittab(dev, ghz5, 0);
+       if (dev->phy.n->ipa2g_on && band == IEEE80211_BAND_2GHZ) {
+               for (i = 0; i < 2; i++) {
+                       offset = i ? B2056_TX1 : B2056_TX0;
+                       if (dev->phy.rev >= 5) {
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_PADG_IDAC, 0xcc);
+                               if (dev->dev->chip_id == 0x4716) {
+                                       bias = 0x40;
+                                       cbias = 0x45;
+                                       pag_boost = 0x5;
+                                       pgag_boost = 0x33;
+                                       mixg_boost = 0x55;
+                               } else {
+                                       bias = 0x25;
+                                       cbias = 0x20;
+                                       pag_boost = 0x4;
+                                       pgag_boost = 0x03;
+                                       mixg_boost = 0x65;
+                               }
+                               padg_boost = 0x77;
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_INTPAG_IMAIN_STAT,
+                                       bias);
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_INTPAG_IAUX_STAT,
+                                       bias);
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_INTPAG_CASCBIAS,
+                                       cbias);
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_INTPAG_BOOST_TUNE,
+                                       pag_boost);
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_PGAG_BOOST_TUNE,
+                                       pgag_boost);
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_PADG_BOOST_TUNE,
+                                       padg_boost);
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_MIXG_BOOST_TUNE,
+                                       mixg_boost);
+                       } else {
+                               bias = dev->phy.is_40mhz ? 0x40 : 0x20;
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_INTPAG_IMAIN_STAT,
+                                       bias);
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_INTPAG_IAUX_STAT,
+                                       bias);
+                               b43_radio_write(dev,
+                                       offset | B2056_TX_INTPAG_CASCBIAS,
+                                       0x30);
+                       }
+                       b43_radio_write(dev, offset | B2056_TX_PA_SPARE1, 0xee);
+               }
+       } else if (dev->phy.n->ipa5g_on && band == IEEE80211_BAND_5GHZ) {
+               /* TODO */
        }
-       b43_radio_init2055_post(dev);
+       udelay(50);
+       /* VCO calibration */
+       b43_radio_write(dev, B2056_SYN_PLL_VCOCAL12, 0x00);
+       b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x38);
+       b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x18);
+       b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x38);
+       b43_radio_write(dev, B2056_TX_INTPAA_PA_MISC, 0x39);
+       udelay(300);
  }
  
  static void b43_radio_init2056_pre(struct b43_wldev *dev)
@@@ -771,830 -693,1013 +693,1013 @@@ static void b43_radio_init2056(struct b
        b43_radio_init2056_post(dev);
  }
  
- /*
-  * Upload the N-PHY tables.
-  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables
-  */
- static void b43_nphy_tables_init(struct b43_wldev *dev)
+ /**************************************************
+  * Radio 0x2055
+  **************************************************/
+ static void b43_chantab_radio_upload(struct b43_wldev *dev,
+                               const struct b43_nphy_channeltab_entry_rev2 *e)
  {
-       if (dev->phy.rev < 3)
-               b43_nphy_rev0_1_2_tables_init(dev);
-       else
-               b43_nphy_rev3plus_tables_init(dev);
- }
+       b43_radio_write(dev, B2055_PLL_REF, e->radio_pll_ref);
+       b43_radio_write(dev, B2055_RF_PLLMOD0, e->radio_rf_pllmod0);
+       b43_radio_write(dev, B2055_RF_PLLMOD1, e->radio_rf_pllmod1);
+       b43_radio_write(dev, B2055_VCO_CAPTAIL, e->radio_vco_captail);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */
- static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable)
- {
-       struct b43_phy_n *nphy = dev->phy.n;
-       enum ieee80211_band band;
-       u16 tmp;
+       b43_radio_write(dev, B2055_VCO_CAL1, e->radio_vco_cal1);
+       b43_radio_write(dev, B2055_VCO_CAL2, e->radio_vco_cal2);
+       b43_radio_write(dev, B2055_PLL_LFC1, e->radio_pll_lfc1);
+       b43_radio_write(dev, B2055_PLL_LFR1, e->radio_pll_lfr1);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
  
-       if (!enable) {
-               nphy->rfctrl_intc1_save = b43_phy_read(dev,
-                                                      B43_NPHY_RFCTL_INTC1);
-               nphy->rfctrl_intc2_save = b43_phy_read(dev,
-                                                      B43_NPHY_RFCTL_INTC2);
-               band = b43_current_band(dev->wl);
-               if (dev->phy.rev >= 3) {
-                       if (band == IEEE80211_BAND_5GHZ)
-                               tmp = 0x600;
-                       else
-                               tmp = 0x480;
-               } else {
-                       if (band == IEEE80211_BAND_5GHZ)
-                               tmp = 0x180;
-                       else
-                               tmp = 0x120;
-               }
-               b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp);
-               b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp);
-       } else {
-               b43_phy_write(dev, B43_NPHY_RFCTL_INTC1,
-                               nphy->rfctrl_intc1_save);
-               b43_phy_write(dev, B43_NPHY_RFCTL_INTC2,
-                               nphy->rfctrl_intc2_save);
-       }
- }
+       b43_radio_write(dev, B2055_PLL_LFC2, e->radio_pll_lfc2);
+       b43_radio_write(dev, B2055_LGBUF_CENBUF, e->radio_lgbuf_cenbuf);
+       b43_radio_write(dev, B2055_LGEN_TUNE1, e->radio_lgen_tune1);
+       b43_radio_write(dev, B2055_LGEN_TUNE2, e->radio_lgen_tune2);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */
- static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
- {
-       u16 tmp;
+       b43_radio_write(dev, B2055_C1_LGBUF_ATUNE, e->radio_c1_lgbuf_atune);
+       b43_radio_write(dev, B2055_C1_LGBUF_GTUNE, e->radio_c1_lgbuf_gtune);
+       b43_radio_write(dev, B2055_C1_RX_RFR1, e->radio_c1_rx_rfr1);
+       b43_radio_write(dev, B2055_C1_TX_PGAPADTN, e->radio_c1_tx_pgapadtn);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
  
-       if (dev->phy.rev >= 3) {
-               if (b43_nphy_ipa(dev)) {
-                       tmp = 4;
-                       b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2,
-                             (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
-               }
+       b43_radio_write(dev, B2055_C1_TX_MXBGTRIM, e->radio_c1_tx_mxbgtrim);
+       b43_radio_write(dev, B2055_C2_LGBUF_ATUNE, e->radio_c2_lgbuf_atune);
+       b43_radio_write(dev, B2055_C2_LGBUF_GTUNE, e->radio_c2_lgbuf_gtune);
+       b43_radio_write(dev, B2055_C2_RX_RFR1, e->radio_c2_rx_rfr1);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
  
-               tmp = 1;
-               b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S2,
-                             (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
-       }
+       b43_radio_write(dev, B2055_C2_TX_PGAPADTN, e->radio_c2_tx_pgapadtn);
+       b43_radio_write(dev, B2055_C2_TX_MXBGTRIM, e->radio_c2_tx_mxbgtrim);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CCA */
- static void b43_nphy_reset_cca(struct b43_wldev *dev)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/Radio/2055Setup */
+ static void b43_radio_2055_setup(struct b43_wldev *dev,
+                               const struct b43_nphy_channeltab_entry_rev2 *e)
  {
-       u16 bbcfg;
+       B43_WARN_ON(dev->phy.rev >= 3);
  
-       b43_phy_force_clock(dev, 1);
-       bbcfg = b43_phy_read(dev, B43_NPHY_BBCFG);
-       b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg | B43_NPHY_BBCFG_RSTCCA);
-       udelay(1);
-       b43_phy_write(dev, B43_NPHY_BBCFG, bbcfg & ~B43_NPHY_BBCFG_RSTCCA);
-       b43_phy_force_clock(dev, 0);
-       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
+       b43_chantab_radio_upload(dev, e);
+       udelay(50);
+       b43_radio_write(dev, B2055_VCO_CAL10, 0x05);
+       b43_radio_write(dev, B2055_VCO_CAL10, 0x45);
+       b43_read32(dev, B43_MMIO_MACCTL); /* flush writes */
+       b43_radio_write(dev, B2055_VCO_CAL10, 0x65);
+       udelay(300);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */
- static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble)
+ static void b43_radio_init2055_pre(struct b43_wldev *dev)
  {
-       u16 mimocfg = b43_phy_read(dev, B43_NPHY_MIMOCFG);
-       mimocfg |= B43_NPHY_MIMOCFG_AUTO;
-       if (preamble == 1)
-               mimocfg |= B43_NPHY_MIMOCFG_GFMIX;
-       else
-               mimocfg &= ~B43_NPHY_MIMOCFG_GFMIX;
-       b43_phy_write(dev, B43_NPHY_MIMOCFG, mimocfg);
+       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+                    ~B43_NPHY_RFCTL_CMD_PORFORCE);
+       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                   B43_NPHY_RFCTL_CMD_CHIP0PU |
+                   B43_NPHY_RFCTL_CMD_OEPORFORCE);
+       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                   B43_NPHY_RFCTL_CMD_PORFORCE);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */
- static void b43_nphy_update_txrx_chain(struct b43_wldev *dev)
+ static void b43_radio_init2055_post(struct b43_wldev *dev)
  {
        struct b43_phy_n *nphy = dev->phy.n;
-       bool override = false;
-       u16 chain = 0x33;
-       if (nphy->txrx_chain == 0) {
-               chain = 0x11;
-               override = true;
-       } else if (nphy->txrx_chain == 1) {
-               chain = 0x22;
-               override = true;
-       }
-       b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
-                       ~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN),
-                       chain);
-       if (override)
-               b43_phy_set(dev, B43_NPHY_RFSEQMODE,
-                               B43_NPHY_RFSEQMODE_CAOVER);
-       else
-               b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
-                               ~B43_NPHY_RFSEQMODE_CAOVER);
- }
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */
- static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est,
-                               u16 samps, u8 time, bool wait)
- {
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
        int i;
-       u16 tmp;
+       u16 val;
+       bool workaround = false;
  
-       b43_phy_write(dev, B43_NPHY_IQEST_SAMCNT, samps);
-       b43_phy_maskset(dev, B43_NPHY_IQEST_WT, ~B43_NPHY_IQEST_WT_VAL, time);
-       if (wait)
-               b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_MODE);
+       if (sprom->revision < 4)
+               workaround = (dev->dev->board_vendor != PCI_VENDOR_ID_BROADCOM
+                             && dev->dev->board_type == 0x46D
+                             && dev->dev->board_rev >= 0x41);
        else
-               b43_phy_mask(dev, B43_NPHY_IQEST_CMD, ~B43_NPHY_IQEST_CMD_MODE);
-       b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_START);
-       for (i = 1000; i; i--) {
-               tmp = b43_phy_read(dev, B43_NPHY_IQEST_CMD);
-               if (!(tmp & B43_NPHY_IQEST_CMD_START)) {
-                       est->i0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI0) << 16) |
-                                       b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO0);
-                       est->q0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI0) << 16) |
-                                       b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO0);
-                       est->iq0_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI0) << 16) |
-                                       b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO0);
+               workaround =
+                       !(sprom->boardflags2_lo & B43_BFL2_RXBB_INT_REG_DIS);
  
-                       est->i1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI1) << 16) |
-                                       b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO1);
-                       est->q1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI1) << 16) |
-                                       b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO1);
-                       est->iq1_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI1) << 16) |
-                                       b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO1);
-                       return;
+       b43_radio_mask(dev, B2055_MASTER1, 0xFFF3);
+       if (workaround) {
+               b43_radio_mask(dev, B2055_C1_RX_BB_REG, 0x7F);
+               b43_radio_mask(dev, B2055_C2_RX_BB_REG, 0x7F);
+       }
+       b43_radio_maskset(dev, B2055_RRCCAL_NOPTSEL, 0xFFC0, 0x2C);
+       b43_radio_write(dev, B2055_CAL_MISC, 0x3C);
+       b43_radio_mask(dev, B2055_CAL_MISC, 0xFFBE);
+       b43_radio_set(dev, B2055_CAL_LPOCTL, 0x80);
+       b43_radio_set(dev, B2055_CAL_MISC, 0x1);
+       msleep(1);
+       b43_radio_set(dev, B2055_CAL_MISC, 0x40);
+       for (i = 0; i < 200; i++) {
+               val = b43_radio_read(dev, B2055_CAL_COUT2);
+               if (val & 0x80) {
+                       i = 0;
+                       break;
                }
                udelay(10);
        }
-       memset(est, 0, sizeof(*est));
+       if (i)
+               b43err(dev->wl, "radio post init timeout\n");
+       b43_radio_mask(dev, B2055_CAL_LPOCTL, 0xFF7F);
+       b43_switch_channel(dev, dev->phy.channel);
+       b43_radio_write(dev, B2055_C1_RX_BB_LPF, 0x9);
+       b43_radio_write(dev, B2055_C2_RX_BB_LPF, 0x9);
+       b43_radio_write(dev, B2055_C1_RX_BB_MIDACHP, 0x83);
+       b43_radio_write(dev, B2055_C2_RX_BB_MIDACHP, 0x83);
+       b43_radio_maskset(dev, B2055_C1_LNA_GAINBST, 0xFFF8, 0x6);
+       b43_radio_maskset(dev, B2055_C2_LNA_GAINBST, 0xFFF8, 0x6);
+       if (!nphy->gain_boost) {
+               b43_radio_set(dev, B2055_C1_RX_RFSPC1, 0x2);
+               b43_radio_set(dev, B2055_C2_RX_RFSPC1, 0x2);
+       } else {
+               b43_radio_mask(dev, B2055_C1_RX_RFSPC1, 0xFFFD);
+               b43_radio_mask(dev, B2055_C2_RX_RFSPC1, 0xFFFD);
+       }
+       udelay(2);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */
- static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write,
-                                       struct b43_phy_n_iq_comp *pcomp)
+ /*
+  * Initialize a Broadcom 2055 N-radio
+  * http://bcm-v4.sipsolutions.net/802.11/Radio/2055/Init
+  */
+ static void b43_radio_init2055(struct b43_wldev *dev)
  {
-       if (write) {
-               b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPA0, pcomp->a0);
-               b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPB0, pcomp->b0);
-               b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPA1, pcomp->a1);
-               b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPB1, pcomp->b1);
+       b43_radio_init2055_pre(dev);
+       if (b43_status(dev) < B43_STAT_INITIALIZED) {
+               /* Follow wl, not specs. Do not force uploading all regs */
+               b2055_upload_inittab(dev, 0, 0);
        } else {
-               pcomp->a0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPA0);
-               pcomp->b0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPB0);
-               pcomp->a1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPA1);
-               pcomp->b1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPB1);
+               bool ghz5 = b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ;
+               b2055_upload_inittab(dev, ghz5, 0);
        }
+       b43_radio_init2055_post(dev);
  }
  
- #if 0
- /* Ready but not used anywhere */
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */
- static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core)
- {
-       u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+ /**************************************************
+  * Samples
+  **************************************************/
  
-       b43_phy_write(dev, B43_NPHY_RFSEQCA, regs[0]);
-       if (core == 0) {
-               b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[1]);
-               b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]);
-       } else {
-               b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]);
-               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]);
-       }
-       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[3]);
-       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[4]);
-       b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, regs[5]);
-       b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, regs[6]);
-       b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, regs[7]);
-       b43_phy_write(dev, B43_NPHY_RFCTL_OVER, regs[8]);
-       b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]);
-       b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]);
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */
+ static int b43_nphy_load_samples(struct b43_wldev *dev,
+                                       struct b43_c32 *samples, u16 len) {
+       struct b43_phy_n *nphy = dev->phy.n;
+       u16 i;
+       u32 *data;
+       data = kzalloc(len * sizeof(u32), GFP_KERNEL);
+       if (!data) {
+               b43err(dev->wl, "allocation for samples loading failed\n");
+               return -ENOMEM;
+       }
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
+       for (i = 0; i < len; i++) {
+               data[i] = (samples[i].i & 0x3FF << 10);
+               data[i] |= samples[i].q & 0x3FF;
+       }
+       b43_ntab_write_bulk(dev, B43_NTAB32(17, 0), len, data);
+       kfree(data);
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+       return 0;
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */
- static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */
+ static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
+                                       bool test)
  {
-       u8 rxval, txval;
-       u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
+       int i;
+       u16 bw, len, rot, angle;
+       struct b43_c32 *samples;
  
-       regs[0] = b43_phy_read(dev, B43_NPHY_RFSEQCA);
-       if (core == 0) {
-               regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
-               regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
-       } else {
-               regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
-               regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
-       }
-       regs[3] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
-       regs[4] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
-       regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1);
-       regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2);
-       regs[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S1);
-       regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER);
-       regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0);
-       regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1);
  
-       b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001);
-       b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001);
+       bw = (dev->phy.is_40mhz) ? 40 : 20;
+       len = bw << 3;
  
-       b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
-                       ~B43_NPHY_RFSEQCA_RXDIS & 0xFFFF,
-                       ((1 - core) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
-       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
-                       ((1 - core) << B43_NPHY_RFSEQCA_TXEN_SHIFT));
-       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN,
-                       (core << B43_NPHY_RFSEQCA_RXEN_SHIFT));
-       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXDIS,
-                       (core << B43_NPHY_RFSEQCA_TXDIS_SHIFT));
+       if (test) {
+               if (b43_phy_read(dev, B43_NPHY_BBCFG) & B43_NPHY_BBCFG_RSTRX)
+                       bw = 82;
+               else
+                       bw = 80;
  
-       if (core == 0) {
-               b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x0007);
-               b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0007);
-       } else {
-               b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x0007);
-               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0007);
+               if (dev->phy.is_40mhz)
+                       bw <<= 1;
+               len = bw << 1;
        }
  
-       b43_nphy_rf_control_intc_override(dev, 2, 0, 3);
-       b43_nphy_rf_control_override(dev, 8, 0, 3, false);
-       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
+       samples = kcalloc(len, sizeof(struct b43_c32), GFP_KERNEL);
+       if (!samples) {
+               b43err(dev->wl, "allocation for samples generation failed\n");
+               return 0;
+       }
+       rot = (((freq * 36) / bw) << 16) / 100;
+       angle = 0;
  
-       if (core == 0) {
-               rxval = 1;
-               txval = 8;
-       } else {
-               rxval = 4;
-               txval = 2;
+       for (i = 0; i < len; i++) {
+               samples[i] = b43_cordic(angle);
+               angle += rot;
+               samples[i].q = CORDIC_CONVERT(samples[i].q * max);
+               samples[i].i = CORDIC_CONVERT(samples[i].i * max);
        }
-       b43_nphy_rf_control_intc_override(dev, 1, rxval, (core + 1));
-       b43_nphy_rf_control_intc_override(dev, 1, txval, (2 - core));
+       i = b43_nphy_load_samples(dev, samples, len);
+       kfree(samples);
+       return (i < 0) ? 0 : len;
  }
- #endif
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */
- static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */
+ static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
+                                       u16 wait, bool iqmode, bool dac_test)
  {
+       struct b43_phy_n *nphy = dev->phy.n;
        int i;
-       s32 iq;
-       u32 ii;
-       u32 qq;
-       int iq_nbits, qq_nbits;
-       int arsh, brsh;
-       u16 tmp, a, b;
+       u16 seq_mode;
+       u32 tmp;
  
-       struct nphy_iq_est est;
-       struct b43_phy_n_iq_comp old;
-       struct b43_phy_n_iq_comp new = { };
-       bool error = false;
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, true);
  
-       if (mask == 0)
-               return;
+       if ((nphy->bb_mult_save & 0x80000000) == 0) {
+               tmp = b43_ntab_read(dev, B43_NTAB16(15, 87));
+               nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
+       }
  
-       b43_nphy_rx_iq_coeffs(dev, false, &old);
-       b43_nphy_rx_iq_coeffs(dev, true, &new);
-       b43_nphy_rx_iq_est(dev, &est, 0x4000, 32, false);
-       new = old;
+       if (!dev->phy.is_40mhz)
+               tmp = 0x6464;
+       else
+               tmp = 0x4747;
+       b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
  
-       for (i = 0; i < 2; i++) {
-               if (i == 0 && (mask & 1)) {
-                       iq = est.iq0_prod;
-                       ii = est.i0_pwr;
-                       qq = est.q0_pwr;
-               } else if (i == 1 && (mask & 2)) {
-                       iq = est.iq1_prod;
-                       ii = est.i1_pwr;
-                       qq = est.q1_pwr;
-               } else {
-                       continue;
-               }
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, false);
  
-               if (ii + qq < 2) {
-                       error = true;
-                       break;
-               }
+       b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1));
  
-               iq_nbits = fls(abs(iq));
-               qq_nbits = fls(qq);
+       if (loops != 0xFFFF)
+               b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, (loops - 1));
+       else
+               b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, loops);
  
-               arsh = iq_nbits - 20;
-               if (arsh >= 0) {
-                       a = -((iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
-                       tmp = ii >> arsh;
-               } else {
-                       a = -((iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
-                       tmp = ii << -arsh;
-               }
-               if (tmp == 0) {
-                       error = true;
-                       break;
-               }
-               a /= tmp;
+       b43_phy_write(dev, B43_NPHY_SAMP_WAITCNT, wait);
  
-               brsh = qq_nbits - 11;
-               if (brsh >= 0) {
-                       b = (qq << (31 - qq_nbits));
-                       tmp = ii >> brsh;
-               } else {
-                       b = (qq << (31 - qq_nbits));
-                       tmp = ii << -brsh;
-               }
-               if (tmp == 0) {
-                       error = true;
-                       break;
-               }
-               b = int_sqrt(b / tmp - a * a) - (1 << 10);
+       seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
  
-               if (i == 0 && (mask & 0x1)) {
-                       if (dev->phy.rev >= 3) {
-                               new.a0 = a & 0x3FF;
-                               new.b0 = b & 0x3FF;
-                       } else {
-                               new.a0 = b & 0x3FF;
-                               new.b0 = a & 0x3FF;
-                       }
-               } else if (i == 1 && (mask & 0x2)) {
-                       if (dev->phy.rev >= 3) {
-                               new.a1 = a & 0x3FF;
-                               new.b1 = b & 0x3FF;
-                       } else {
-                               new.a1 = b & 0x3FF;
-                               new.b1 = a & 0x3FF;
-                       }
+       b43_phy_set(dev, B43_NPHY_RFSEQMODE, B43_NPHY_RFSEQMODE_CAOVER);
+       if (iqmode) {
+               b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
+               b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000);
+       } else {
+               if (dac_test)
+                       b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5);
+               else
+                       b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
+       }
+       for (i = 0; i < 100; i++) {
+               if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) {
+                       i = 0;
+                       break;
                }
+               udelay(10);
        }
+       if (i)
+               b43err(dev->wl, "run samples timeout\n");
  
-       if (error)
-               new = old;
-       b43_nphy_rx_iq_coeffs(dev, true, &new);
+       b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */
- static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev)
+ /**************************************************
+  * RSSI
+  **************************************************/
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */
+ static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
+                                       s8 offset, u8 core, u8 rail,
+                                       enum b43_nphy_rssi_type type)
  {
-       u16 array[4];
-       b43_ntab_read_bulk(dev, B43_NTAB16(0xF, 0x50), 4, array);
+       u16 tmp;
+       bool core1or5 = (core == 1) || (core == 5);
+       bool core2or5 = (core == 2) || (core == 5);
  
-       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW0, array[0]);
-       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW1, array[1]);
-       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW2, array[2]);
-       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]);
- }
+       offset = clamp_val(offset, -32, 31);
+       tmp = ((scale & 0x3F) << 8) | (offset & 0x3F);
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
- static void b43_nphy_write_clip_detection(struct b43_wldev *dev,
-                                         const u16 *clip_st)
- {
-       b43_phy_write(dev, B43_NPHY_C1_CLIP1THRES, clip_st[0]);
-       b43_phy_write(dev, B43_NPHY_C2_CLIP1THRES, clip_st[1]);
- }
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp);
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp);
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/clip-detection */
- static void b43_nphy_read_clip_detection(struct b43_wldev *dev, u16 *clip_st)
- {
-       clip_st[0] = b43_phy_read(dev, B43_NPHY_C1_CLIP1THRES);
-       clip_st[1] = b43_phy_read(dev, B43_NPHY_C2_CLIP1THRES);
- }
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp);
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp);
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp);
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp);
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */
- static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
- {
-       if (dev->phy.rev >= 3) {
-               if (!init)
-                       return;
-               if (0 /* FIXME */) {
-                       b43_ntab_write(dev, B43_NTAB16(9, 2), 0x211);
-                       b43_ntab_write(dev, B43_NTAB16(9, 3), 0x222);
-                       b43_ntab_write(dev, B43_NTAB16(9, 8), 0x144);
-                       b43_ntab_write(dev, B43_NTAB16(9, 12), 0x188);
-               }
-       } else {
-               b43_phy_write(dev, B43_NPHY_GPIO_LOOEN, 0);
-               b43_phy_write(dev, B43_NPHY_GPIO_HIOEN, 0);
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp);
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp);
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
  
-               switch (dev->dev->bus_type) {
- #ifdef CONFIG_B43_BCMA
-               case B43_BUS_BCMA:
-                       bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc,
-                                                0xFC00, 0xFC00);
-                       break;
- #endif
- #ifdef CONFIG_B43_SSB
-               case B43_BUS_SSB:
-                       ssb_chipco_gpio_control(&dev->dev->sdev->bus->chipco,
-                                               0xFC00, 0xFC00);
-                       break;
- #endif
-               }
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp);
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp);
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp);
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp);
  
-               b43_write32(dev, B43_MMIO_MACCTL,
-                       b43_read32(dev, B43_MMIO_MACCTL) &
-                       ~B43_MACCTL_GPOUTSMSK);
-               b43_write16(dev, B43_MMIO_GPIO_MASK,
-                       b43_read16(dev, B43_MMIO_GPIO_MASK) | 0xFC00);
-               b43_write16(dev, B43_MMIO_GPIO_CONTROL,
-                       b43_read16(dev, B43_MMIO_GPIO_CONTROL) & ~0xFC00);
+       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp);
+       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp);
+       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp);
+       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp);
  
-               if (init) {
-                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
-                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
-                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
-                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
-               }
-       }
+       if (core1or5 && (type == B43_NPHY_RSSI_TSSI_I))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp);
+       if (core2or5 && (type == B43_NPHY_RSSI_TSSI_I))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp);
+       if (core1or5 && (type == B43_NPHY_RSSI_TSSI_Q))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp);
+       if (core2or5 && (type == B43_NPHY_RSSI_TSSI_Q))
+               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/classifier */
- static u16 b43_nphy_classifier(struct b43_wldev *dev, u16 mask, u16 val)
+ static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
  {
-       u16 tmp;
+       u8 i;
+       u16 reg, val;
  
-       if (dev->dev->core_rev == 16)
-               b43_mac_suspend(dev);
+       if (code == 0) {
+               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, 0xFDFF);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, 0xFDFF);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C1, 0xFCFF);
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C2, 0xFCFF);
+               b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S0, 0xFFDF);
+               b43_phy_mask(dev, B43_NPHY_TXF_40CO_B32S1, 0xFFDF);
+               b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0xFFC3);
+               b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0xFFC3);
+       } else {
+               for (i = 0; i < 2; i++) {
+                       if ((code == 1 && i == 1) || (code == 2 && !i))
+                               continue;
  
-       tmp = b43_phy_read(dev, B43_NPHY_CLASSCTL);
-       tmp &= (B43_NPHY_CLASSCTL_CCKEN | B43_NPHY_CLASSCTL_OFDMEN |
-               B43_NPHY_CLASSCTL_WAITEDEN);
-       tmp &= ~mask;
-       tmp |= (val & mask);
-       b43_phy_maskset(dev, B43_NPHY_CLASSCTL, 0xFFF8, tmp);
+                       reg = (i == 0) ?
+                               B43_NPHY_AFECTL_OVER1 : B43_NPHY_AFECTL_OVER;
+                       b43_phy_maskset(dev, reg, 0xFDFF, 0x0200);
  
-       if (dev->dev->core_rev == 16)
-               b43_mac_enable(dev);
+                       if (type < 3) {
+                               reg = (i == 0) ?
+                                       B43_NPHY_AFECTL_C1 :
+                                       B43_NPHY_AFECTL_C2;
+                               b43_phy_maskset(dev, reg, 0xFCFF, 0);
  
-       return tmp;
- }
+                               reg = (i == 0) ?
+                                       B43_NPHY_RFCTL_LUT_TRSW_UP1 :
+                                       B43_NPHY_RFCTL_LUT_TRSW_UP2;
+                               b43_phy_maskset(dev, reg, 0xFFC3, 0);
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/carriersearch */
- static void b43_nphy_stay_in_carrier_search(struct b43_wldev *dev, bool enable)
- {
-       struct b43_phy *phy = &dev->phy;
-       struct b43_phy_n *nphy = phy->n;
+                               if (type == 0)
+                                       val = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? 4 : 8;
+                               else if (type == 1)
+                                       val = 16;
+                               else
+                                       val = 32;
+                               b43_phy_set(dev, reg, val);
  
-       if (enable) {
-               static const u16 clip[] = { 0xFFFF, 0xFFFF };
-               if (nphy->deaf_count++ == 0) {
-                       nphy->classifier_state = b43_nphy_classifier(dev, 0, 0);
-                       b43_nphy_classifier(dev, 0x7, 0);
-                       b43_nphy_read_clip_detection(dev, nphy->clip_state);
-                       b43_nphy_write_clip_detection(dev, clip);
-               }
-               b43_nphy_reset_cca(dev);
-       } else {
-               if (--nphy->deaf_count == 0) {
-                       b43_nphy_classifier(dev, 0x7, nphy->classifier_state);
-                       b43_nphy_write_clip_detection(dev, nphy->clip_state);
-               }
-       }
- }
+                               reg = (i == 0) ?
+                                       B43_NPHY_TXF_40CO_B1S0 :
+                                       B43_NPHY_TXF_40CO_B32S1;
+                               b43_phy_set(dev, reg, 0x0020);
+                       } else {
+                               if (type == 6)
+                                       val = 0x0100;
+                               else if (type == 3)
+                                       val = 0x0200;
+                               else
+                                       val = 0x0300;
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
- static void b43_nphy_stop_playback(struct b43_wldev *dev)
- {
-       struct b43_phy_n *nphy = dev->phy.n;
-       u16 tmp;
+                               reg = (i == 0) ?
+                                       B43_NPHY_AFECTL_C1 :
+                                       B43_NPHY_AFECTL_C2;
  
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 1);
+                               b43_phy_maskset(dev, reg, 0xFCFF, val);
+                               b43_phy_maskset(dev, reg, 0xF3FF, val << 2);
  
-       tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT);
-       if (tmp & 0x1)
-               b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
-       else if (tmp & 0x2)
-               b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
+                               if (type != 3 && type != 6) {
+                                       enum ieee80211_band band =
+                                               b43_current_band(dev->wl);
  
-       b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
+                                       if (b43_nphy_ipa(dev))
+                                               val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE;
+                                       else
+                                               val = 0x11;
+                                       reg = (i == 0) ? 0x2000 : 0x3000;
+                                       reg |= B2055_PADDRV;
+                                       b43_radio_write16(dev, reg, val);
  
-       if (nphy->bb_mult_save & 0x80000000) {
-               tmp = nphy->bb_mult_save & 0xFFFF;
-               b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
-               nphy->bb_mult_save = 0;
+                                       reg = (i == 0) ?
+                                               B43_NPHY_AFECTL_OVER1 :
+                                               B43_NPHY_AFECTL_OVER;
+                                       b43_phy_set(dev, reg, 0x0200);
+                               }
+                       }
+               }
        }
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */
- static void b43_nphy_spur_workaround(struct b43_wldev *dev)
+ static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
  {
-       struct b43_phy_n *nphy = dev->phy.n;
-       u8 channel = dev->phy.channel;
-       int tone[2] = { 57, 58 };
-       u32 noise[2] = { 0x3FF, 0x3FF };
+       u16 val;
  
-       B43_WARN_ON(dev->phy.rev < 3);
+       if (type < 3)
+               val = 0;
+       else if (type == 6)
+               val = 1;
+       else if (type == 3)
+               val = 2;
+       else
+               val = 3;
  
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 1);
+       val = (val << 12) | (val << 14);
+       b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
+       b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
  
-       if (nphy->gband_spurwar_en) {
-               /* TODO: N PHY Adjust Analog Pfbw (7) */
-               if (channel == 11 && dev->phy.is_40mhz)
-                       ; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/
-               else
-                       ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
-               /* TODO: N PHY Adjust CRS Min Power (0x1E) */
+       if (type < 3) {
+               b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
+                               (type + 1) << 4);
+               b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
+                               (type + 1) << 4);
        }
  
-       if (nphy->aband_spurwar_en) {
-               if (channel == 54) {
-                       tone[0] = 0x20;
-                       noise[0] = 0x25F;
-               } else if (channel == 38 || channel == 102 || channel == 118) {
-                       if (0 /* FIXME */) {
-                               tone[0] = 0x20;
-                               noise[0] = 0x21F;
-                       } else {
-                               tone[0] = 0;
-                               noise[0] = 0;
-                       }
-               } else if (channel == 134) {
-                       tone[0] = 0x20;
-                       noise[0] = 0x21F;
-               } else if (channel == 151) {
-                       tone[0] = 0x10;
-                       noise[0] = 0x23F;
-               } else if (channel == 153 || channel == 161) {
-                       tone[0] = 0x30;
-                       noise[0] = 0x23F;
-               } else {
-                       tone[0] = 0;
-                       noise[0] = 0;
+       if (code == 0) {
+               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x3000);
+               if (type < 3) {
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+                               ~(B43_NPHY_RFCTL_CMD_RXEN |
+                                 B43_NPHY_RFCTL_CMD_CORESEL));
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER,
+                               ~(0x1 << 12 |
+                                 0x1 << 5 |
+                                 0x1 << 1 |
+                                 0x1));
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
+                               ~B43_NPHY_RFCTL_CMD_START);
+                       udelay(20);
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
+               }
+       } else {
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x3000);
+               if (type < 3) {
+                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
+                               ~(B43_NPHY_RFCTL_CMD_RXEN |
+                                 B43_NPHY_RFCTL_CMD_CORESEL),
+                               (B43_NPHY_RFCTL_CMD_RXEN |
+                                code << B43_NPHY_RFCTL_CMD_CORESEL_SHIFT));
+                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER,
+                               (0x1 << 12 |
+                                 0x1 << 5 |
+                                 0x1 << 1 |
+                                 0x1));
+                       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
+                               B43_NPHY_RFCTL_CMD_START);
+                       udelay(20);
+                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
                }
-               if (!tone[0] && !noise[0])
-                       ; /* TODO: N PHY Adjust Min Noise Var(1, tone, noise)*/
-               else
-                       ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
        }
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/AdjustLnaGainTbl */
- static void b43_nphy_adjust_lna_gain_table(struct b43_wldev *dev)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
+ static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
  {
-       struct b43_phy_n *nphy = dev->phy.n;
-       u8 i;
-       s16 tmp;
-       u16 data[4];
-       s16 gain[2];
-       u16 minmax[2];
-       static const u16 lna_gain[4] = { -2, 10, 19, 25 };
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 1);
-       if (nphy->gain_boost) {
-               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-                       gain[0] = 6;
-                       gain[1] = 6;
-               } else {
-                       tmp = 40370 - 315 * dev->phy.channel;
-                       gain[0] = ((tmp >> 13) + ((tmp >> 12) & 1));
-                       tmp = 23242 - 224 * dev->phy.channel;
-                       gain[1] = ((tmp >> 13) + ((tmp >> 12) & 1));
-               }
-       } else {
-               gain[0] = 0;
-               gain[1] = 0;
-       }
+       if (dev->phy.rev >= 3)
+               b43_nphy_rev3_rssi_select(dev, code, type);
+       else
+               b43_nphy_rev2_rssi_select(dev, code, type);
+ }
  
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */
+ static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf)
+ {
+       int i;
        for (i = 0; i < 2; i++) {
-               if (nphy->elna_gain_config) {
-                       data[0] = 19 + gain[i];
-                       data[1] = 25 + gain[i];
-                       data[2] = 25 + gain[i];
-                       data[3] = 25 + gain[i];
+               if (type == 2) {
+                       if (i == 0) {
+                               b43_radio_maskset(dev, B2055_C1_B0NB_RSSIVCM,
+                                                 0xFC, buf[0]);
+                               b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
+                                                 0xFC, buf[1]);
+                       } else {
+                               b43_radio_maskset(dev, B2055_C2_B0NB_RSSIVCM,
+                                                 0xFC, buf[2 * i]);
+                               b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
+                                                 0xFC, buf[2 * i + 1]);
+                       }
                } else {
-                       data[0] = lna_gain[0] + gain[i];
-                       data[1] = lna_gain[1] + gain[i];
-                       data[2] = lna_gain[2] + gain[i];
-                       data[3] = lna_gain[3] + gain[i];
+                       if (i == 0)
+                               b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
+                                                 0xF3, buf[0] << 2);
+                       else
+                               b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
+                                                 0xF3, buf[2 * i + 1] << 2);
                }
-               b43_ntab_write_bulk(dev, B43_NTAB16(i, 8), 4, data);
-               minmax[i] = 23 + gain[i];
        }
-       b43_phy_maskset(dev, B43_NPHY_C1_MINMAX_GAIN, ~B43_NPHY_C1_MINGAIN,
-                               minmax[0] << B43_NPHY_C1_MINGAIN_SHIFT);
-       b43_phy_maskset(dev, B43_NPHY_C2_MINMAX_GAIN, ~B43_NPHY_C2_MINGAIN,
-                               minmax[1] << B43_NPHY_C2_MINGAIN_SHIFT);
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
- static void b43_nphy_gain_ctrl_workarounds(struct b43_wldev *dev)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */
+ static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
+                               u8 nsamp)
  {
-       struct b43_phy_n *nphy = dev->phy.n;
-       struct ssb_sprom *sprom = dev->dev->bus_sprom;
-       /* PHY rev 0, 1, 2 */
-       u8 i, j;
-       u8 code;
-       u16 tmp;
-       u8 rfseq_events[3] = { 6, 8, 7 };
-       u8 rfseq_delays[3] = { 10, 30, 1 };
-       /* PHY rev >= 3 */
-       bool ghz5;
-       bool ext_lna;
-       u16 rssi_gain;
-       struct nphy_gain_ctl_workaround_entry *e;
-       u8 lpf_gain[6] = { 0x00, 0x06, 0x0C, 0x12, 0x12, 0x12 };
-       u8 lpf_bits[6] = { 0, 1, 2, 3, 3, 3 };
+       int i;
+       int out;
+       u16 save_regs_phy[9];
+       u16 s[2];
  
        if (dev->phy.rev >= 3) {
-               /* Prepare values */
-               ghz5 = b43_phy_read(dev, B43_NPHY_BANDCTL)
-                       & B43_NPHY_BANDCTL_5GHZ;
-               ext_lna = sprom->boardflags_lo & B43_BFL_EXTLNA;
-               e = b43_nphy_get_gain_ctl_workaround_ent(dev, ghz5, ext_lna);
-               if (ghz5 && dev->phy.rev >= 5)
-                       rssi_gain = 0x90;
-               else
-                       rssi_gain = 0x50;
-               b43_phy_set(dev, B43_NPHY_RXCTL, 0x0040);
-               /* Set Clip 2 detect */
-               b43_phy_set(dev, B43_NPHY_C1_CGAINI,
-                               B43_NPHY_C1_CGAINI_CL2DETECT);
-               b43_phy_set(dev, B43_NPHY_C2_CGAINI,
-                               B43_NPHY_C2_CGAINI_CL2DETECT);
-               b43_radio_write(dev, B2056_RX0 | B2056_RX_BIASPOLE_LNAG1_IDAC,
-                               0x17);
-               b43_radio_write(dev, B2056_RX1 | B2056_RX_BIASPOLE_LNAG1_IDAC,
-                               0x17);
-               b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAG2_IDAC, 0xF0);
-               b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAG2_IDAC, 0xF0);
-               b43_radio_write(dev, B2056_RX0 | B2056_RX_RSSI_POLE, 0x00);
-               b43_radio_write(dev, B2056_RX1 | B2056_RX_RSSI_POLE, 0x00);
-               b43_radio_write(dev, B2056_RX0 | B2056_RX_RSSI_GAIN,
-                               rssi_gain);
-               b43_radio_write(dev, B2056_RX1 | B2056_RX_RSSI_GAIN,
-                               rssi_gain);
-               b43_radio_write(dev, B2056_RX0 | B2056_RX_BIASPOLE_LNAA1_IDAC,
-                               0x17);
-               b43_radio_write(dev, B2056_RX1 | B2056_RX_BIASPOLE_LNAA1_IDAC,
-                               0x17);
-               b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAA2_IDAC, 0xFF);
-               b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAA2_IDAC, 0xFF);
-               b43_ntab_write_bulk(dev, B43_NTAB8(0, 8), 4, e->lna1_gain);
-               b43_ntab_write_bulk(dev, B43_NTAB8(1, 8), 4, e->lna1_gain);
-               b43_ntab_write_bulk(dev, B43_NTAB8(0, 16), 4, e->lna2_gain);
-               b43_ntab_write_bulk(dev, B43_NTAB8(1, 16), 4, e->lna2_gain);
-               b43_ntab_write_bulk(dev, B43_NTAB8(0, 32), 10, e->gain_db);
-               b43_ntab_write_bulk(dev, B43_NTAB8(1, 32), 10, e->gain_db);
-               b43_ntab_write_bulk(dev, B43_NTAB8(2, 32), 10, e->gain_bits);
-               b43_ntab_write_bulk(dev, B43_NTAB8(3, 32), 10, e->gain_bits);
-               b43_ntab_write_bulk(dev, B43_NTAB8(0, 0x40), 6, lpf_gain);
-               b43_ntab_write_bulk(dev, B43_NTAB8(1, 0x40), 6, lpf_gain);
-               b43_ntab_write_bulk(dev, B43_NTAB8(2, 0x40), 6, lpf_bits);
-               b43_ntab_write_bulk(dev, B43_NTAB8(3, 0x40), 6, lpf_bits);
-               b43_phy_write(dev, B43_NPHY_C1_INITGAIN, e->init_gain);
-               b43_phy_write(dev, 0x2A7, e->init_gain);
-               b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x106), 2,
-                                       e->rfseq_init);
-               b43_phy_write(dev, B43_NPHY_C1_INITGAIN, e->init_gain);
-               /* TODO: check defines. Do not match variables names */
-               b43_phy_write(dev, B43_NPHY_C1_CLIP1_MEDGAIN, e->cliphi_gain);
-               b43_phy_write(dev, 0x2A9, e->cliphi_gain);
-               b43_phy_write(dev, B43_NPHY_C1_CLIP2_GAIN, e->clipmd_gain);
-               b43_phy_write(dev, 0x2AB, e->clipmd_gain);
-               b43_phy_write(dev, B43_NPHY_C2_CLIP1_HIGAIN, e->cliplo_gain);
-               b43_phy_write(dev, 0x2AD, e->cliplo_gain);
-               b43_phy_maskset(dev, 0x27D, 0xFF00, e->crsmin);
-               b43_phy_maskset(dev, 0x280, 0xFF00, e->crsminl);
-               b43_phy_maskset(dev, 0x283, 0xFF00, e->crsminu);
-               b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, e->nbclip);
-               b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, e->nbclip);
-               b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
-                               ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, e->wlclip);
-               b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
-                               ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, e->wlclip);
-               b43_phy_write(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
+               save_regs_phy[0] = b43_phy_read(dev,
+                                               B43_NPHY_RFCTL_LUT_TRSW_UP1);
+               save_regs_phy[1] = b43_phy_read(dev,
+                                               B43_NPHY_RFCTL_LUT_TRSW_UP2);
+               save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+               save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+               save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
+               save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+               save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0);
+               save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1);
+               save_regs_phy[8] = 0;
        } else {
-               /* Set Clip 2 detect */
-               b43_phy_set(dev, B43_NPHY_C1_CGAINI,
-                               B43_NPHY_C1_CGAINI_CL2DETECT);
-               b43_phy_set(dev, B43_NPHY_C2_CGAINI,
-                               B43_NPHY_C2_CGAINI_CL2DETECT);
-               /* Set narrowband clip threshold */
-               b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84);
-               b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
-               if (!dev->phy.is_40mhz) {
-                       /* Set dwell lengths */
-                       b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
-                       b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
-                       b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009);
-                       b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009);
-               }
+               save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+               save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+               save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+               save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_RFCTL_CMD);
+               save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER);
+               save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1);
+               save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2);
+               save_regs_phy[7] = 0;
+               save_regs_phy[8] = 0;
+       }
  
-               /* Set wideband clip 2 threshold */
-               b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
-                               ~B43_NPHY_C1_CLIPWBTHRES_CLIP2,
-                               21);
-               b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
-                               ~B43_NPHY_C2_CLIPWBTHRES_CLIP2,
-                               21);
-               if (!dev->phy.is_40mhz) {
-                       b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
-                               ~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1);
-                       b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
-                               ~B43_NPHY_C2_CGAINI_GAINBKOFF, 0x1);
-                       b43_phy_maskset(dev, B43_NPHY_C1_CCK_CGAINI,
-                               ~B43_NPHY_C1_CCK_CGAINI_GAINBKOFF, 0x1);
-                       b43_phy_maskset(dev, B43_NPHY_C2_CCK_CGAINI,
-                               ~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1);
-               }
+       b43_nphy_rssi_select(dev, 5, type);
  
-               b43_phy_write(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
+       if (dev->phy.rev < 2) {
+               save_regs_phy[8] = b43_phy_read(dev, B43_NPHY_GPIO_SEL);
+               b43_phy_write(dev, B43_NPHY_GPIO_SEL, 5);
+       }
  
-               if (nphy->gain_boost) {
-                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ &&
-                           dev->phy.is_40mhz)
-                               code = 4;
-                       else
-                               code = 5;
+       for (i = 0; i < 4; i++)
+               buf[i] = 0;
+       for (i = 0; i < nsamp; i++) {
+               if (dev->phy.rev < 2) {
+                       s[0] = b43_phy_read(dev, B43_NPHY_GPIO_LOOUT);
+                       s[1] = b43_phy_read(dev, B43_NPHY_GPIO_HIOUT);
                } else {
-                       code = dev->phy.is_40mhz ? 6 : 7;
+                       s[0] = b43_phy_read(dev, B43_NPHY_RSSI1);
+                       s[1] = b43_phy_read(dev, B43_NPHY_RSSI2);
                }
  
-               /* Set HPVGA2 index */
-               b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN,
-                               ~B43_NPHY_C1_INITGAIN_HPVGA2,
-                               code << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
-               b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN,
-                               ~B43_NPHY_C2_INITGAIN_HPVGA2,
-                               code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+               buf[0] += ((s8)((s[0] & 0x3F) << 2)) >> 2;
+               buf[1] += ((s8)(((s[0] >> 8) & 0x3F) << 2)) >> 2;
+               buf[2] += ((s8)((s[1] & 0x3F) << 2)) >> 2;
+               buf[3] += ((s8)(((s[1] >> 8) & 0x3F) << 2)) >> 2;
+       }
+       out = (buf[0] & 0xFF) << 24 | (buf[1] & 0xFF) << 16 |
+               (buf[2] & 0xFF) << 8 | (buf[3] & 0xFF);
  
-               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
-               /* specs say about 2 loops, but wl does 4 */
-               for (i = 0; i < 4; i++)
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
-                                                       (code << 8 | 0x7C));
+       if (dev->phy.rev < 2)
+               b43_phy_write(dev, B43_NPHY_GPIO_SEL, save_regs_phy[8]);
  
-               b43_nphy_adjust_lna_gain_table(dev);
+       if (dev->phy.rev >= 3) {
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1,
+                               save_regs_phy[0]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2,
+                               save_regs_phy[1]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[2]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[3]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, save_regs_phy[4]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]);
+               b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]);
+               b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]);
+       } else {
+               b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[0]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[1]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[2]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_CMD, save_regs_phy[3]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_OVER, save_regs_phy[4]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, save_regs_phy[5]);
+               b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, save_regs_phy[6]);
+       }
  
-               if (nphy->elna_gain_config) {
-                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0808);
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
-                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0C08);
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
-                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
-                       /* specs say about 2 loops, but wl does 4 */
-                       for (i = 0; i < 4; i++)
-                               b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
-                                                       (code << 8 | 0x74));
-               }
+       return out;
+ }
  
-               if (dev->phy.rev == 2) {
-                       for (i = 0; i < 4; i++) {
-                               b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
-                                               (0x0400 * i) + 0x0020);
-                               for (j = 0; j < 21; j++) {
-                                       tmp = j * (i < 2 ? 3 : 1);
-                                       b43_phy_write(dev,
-                                               B43_NPHY_TABLE_DATALO, tmp);
-                               }
-                       }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */
+ static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
+ {
+       int i, j;
+       u8 state[4];
+       u8 code, val;
+       u16 class, override;
+       u8 regs_save_radio[2];
+       u16 regs_save_phy[2];
+       s8 offset[4];
+       u8 core;
+       u8 rail;
+       u16 clip_state[2];
+       u16 clip_off[2] = { 0xFFFF, 0xFFFF };
+       s32 results_min[4] = { };
+       u8 vcm_final[4] = { };
+       s32 results[4][4] = { };
+       s32 miniq[4][2] = { };
+       if (type == 2) {
+               code = 0;
+               val = 6;
+       } else if (type < 2) {
+               code = 25;
+               val = 4;
+       } else {
+               B43_WARN_ON(1);
+               return;
+       }
+       class = b43_nphy_classifier(dev, 0, 0);
+       b43_nphy_classifier(dev, 7, 4);
+       b43_nphy_read_clip_detection(dev, clip_state);
+       b43_nphy_write_clip_detection(dev, clip_off);
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
+               override = 0x140;
+       else
+               override = 0x110;
+       regs_save_phy[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+       regs_save_radio[0] = b43_radio_read16(dev, B2055_C1_PD_RXTX);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, override);
+       b43_radio_write16(dev, B2055_C1_PD_RXTX, val);
+       regs_save_phy[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+       regs_save_radio[1] = b43_radio_read16(dev, B2055_C2_PD_RXTX);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, override);
+       b43_radio_write16(dev, B2055_C2_PD_RXTX, val);
+       state[0] = b43_radio_read16(dev, B2055_C1_PD_RSSIMISC) & 0x07;
+       state[1] = b43_radio_read16(dev, B2055_C2_PD_RSSIMISC) & 0x07;
+       b43_radio_mask(dev, B2055_C1_PD_RSSIMISC, 0xF8);
+       b43_radio_mask(dev, B2055_C2_PD_RSSIMISC, 0xF8);
+       state[2] = b43_radio_read16(dev, B2055_C1_SP_RSSI) & 0x07;
+       state[3] = b43_radio_read16(dev, B2055_C2_SP_RSSI) & 0x07;
+       b43_nphy_rssi_select(dev, 5, type);
+       b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 0, type);
+       b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 1, type);
+       for (i = 0; i < 4; i++) {
+               u8 tmp[4];
+               for (j = 0; j < 4; j++)
+                       tmp[j] = i;
+               if (type != 1)
+                       b43_nphy_set_rssi_2055_vcm(dev, type, tmp);
+               b43_nphy_poll_rssi(dev, type, results[i], 8);
+               if (type < 2)
+                       for (j = 0; j < 2; j++)
+                               miniq[i][j] = min(results[i][2 * j],
+                                               results[i][2 * j + 1]);
+       }
+       for (i = 0; i < 4; i++) {
+               s32 mind = 40;
+               u8 minvcm = 0;
+               s32 minpoll = 249;
+               s32 curr;
+               for (j = 0; j < 4; j++) {
+                       if (type == 2)
+                               curr = abs(results[j][i]);
+                       else
+                               curr = abs(miniq[j][i / 2] - code * 8);
+                       if (curr < mind) {
+                               mind = curr;
+                               minvcm = j;
+                       }
+                       if (results[j][i] < minpoll)
+                               minpoll = results[j][i];
                }
+               results_min[i] = minpoll;
+               vcm_final[i] = minvcm;
+       }
  
-               b43_nphy_set_rf_sequence(dev, 5,
-                               rfseq_events, rfseq_delays, 3);
-               b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
-                       ~B43_NPHY_OVER_DGAIN_CCKDGECV & 0xFFFF,
-                       0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
+       if (type != 1)
+               b43_nphy_set_rssi_2055_vcm(dev, type, vcm_final);
  
-               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
-                       b43_phy_maskset(dev, B43_PHY_N(0xC5D),
-                                       0xFF80, 4);
+       for (i = 0; i < 4; i++) {
+               offset[i] = (code * 8) - results[vcm_final[i]][i];
+               if (offset[i] < 0)
+                       offset[i] = -((abs(offset[i]) + 4) / 8);
+               else
+                       offset[i] = (offset[i] + 4) / 8;
+               if (results_min[i] == 248)
+                       offset[i] = code - 32;
+               core = (i / 2) ? 2 : 1;
+               rail = (i % 2) ? 1 : 0;
+               b43_nphy_scale_offset_rssi(dev, 0, offset[i], core, rail,
+                                               type);
+       }
+       b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]);
+       b43_radio_maskset(dev, B2055_C2_PD_RSSIMISC, 0xF8, state[1]);
+       switch (state[2]) {
+       case 1:
+               b43_nphy_rssi_select(dev, 1, 2);
+               break;
+       case 4:
+               b43_nphy_rssi_select(dev, 1, 0);
+               break;
+       case 2:
+               b43_nphy_rssi_select(dev, 1, 1);
+               break;
+       default:
+               b43_nphy_rssi_select(dev, 1, 1);
+               break;
+       }
+       switch (state[3]) {
+       case 1:
+               b43_nphy_rssi_select(dev, 2, 2);
+               break;
+       case 4:
+               b43_nphy_rssi_select(dev, 2, 0);
+               break;
+       default:
+               b43_nphy_rssi_select(dev, 2, 1);
+               break;
+       }
+       b43_nphy_rssi_select(dev, 0, type);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs_save_phy[0]);
+       b43_radio_write16(dev, B2055_C1_PD_RXTX, regs_save_radio[0]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs_save_phy[1]);
+       b43_radio_write16(dev, B2055_C2_PD_RXTX, regs_save_radio[1]);
+       b43_nphy_classifier(dev, 7, class);
+       b43_nphy_write_clip_detection(dev, clip_state);
+       /* Specs don't say about reset here, but it makes wl and b43 dumps
+          identical, it really seems wl performs this */
+       b43_nphy_reset_cca(dev);
+ }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
+ static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
+ {
+       /* TODO */
+ }
+ /*
+  * RSSI Calibration
+  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal
+  */
+ static void b43_nphy_rssi_cal(struct b43_wldev *dev)
+ {
+       if (dev->phy.rev >= 3) {
+               b43_nphy_rev3_rssi_cal(dev);
+       } else {
+               b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Z);
+               b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_X);
+               b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Y);
+       }
+ }
+ /**************************************************
+  * Workarounds
+  **************************************************/
+ static void b43_nphy_gain_ctl_workarounds_rev3plus(struct b43_wldev *dev)
+ {
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
+       bool ghz5;
+       bool ext_lna;
+       u16 rssi_gain;
+       struct nphy_gain_ctl_workaround_entry *e;
+       u8 lpf_gain[6] = { 0x00, 0x06, 0x0C, 0x12, 0x12, 0x12 };
+       u8 lpf_bits[6] = { 0, 1, 2, 3, 3, 3 };
+       /* Prepare values */
+       ghz5 = b43_phy_read(dev, B43_NPHY_BANDCTL)
+               & B43_NPHY_BANDCTL_5GHZ;
+       ext_lna = sprom->boardflags_lo & B43_BFL_EXTLNA;
+       e = b43_nphy_get_gain_ctl_workaround_ent(dev, ghz5, ext_lna);
+       if (ghz5 && dev->phy.rev >= 5)
+               rssi_gain = 0x90;
+       else
+               rssi_gain = 0x50;
+       b43_phy_set(dev, B43_NPHY_RXCTL, 0x0040);
+       /* Set Clip 2 detect */
+       b43_phy_set(dev, B43_NPHY_C1_CGAINI,
+                       B43_NPHY_C1_CGAINI_CL2DETECT);
+       b43_phy_set(dev, B43_NPHY_C2_CGAINI,
+                       B43_NPHY_C2_CGAINI_CL2DETECT);
+       b43_radio_write(dev, B2056_RX0 | B2056_RX_BIASPOLE_LNAG1_IDAC,
+                       0x17);
+       b43_radio_write(dev, B2056_RX1 | B2056_RX_BIASPOLE_LNAG1_IDAC,
+                       0x17);
+       b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAG2_IDAC, 0xF0);
+       b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAG2_IDAC, 0xF0);
+       b43_radio_write(dev, B2056_RX0 | B2056_RX_RSSI_POLE, 0x00);
+       b43_radio_write(dev, B2056_RX1 | B2056_RX_RSSI_POLE, 0x00);
+       b43_radio_write(dev, B2056_RX0 | B2056_RX_RSSI_GAIN,
+                       rssi_gain);
+       b43_radio_write(dev, B2056_RX1 | B2056_RX_RSSI_GAIN,
+                       rssi_gain);
+       b43_radio_write(dev, B2056_RX0 | B2056_RX_BIASPOLE_LNAA1_IDAC,
+                       0x17);
+       b43_radio_write(dev, B2056_RX1 | B2056_RX_BIASPOLE_LNAA1_IDAC,
+                       0x17);
+       b43_radio_write(dev, B2056_RX0 | B2056_RX_LNAA2_IDAC, 0xFF);
+       b43_radio_write(dev, B2056_RX1 | B2056_RX_LNAA2_IDAC, 0xFF);
+       b43_ntab_write_bulk(dev, B43_NTAB8(0, 8), 4, e->lna1_gain);
+       b43_ntab_write_bulk(dev, B43_NTAB8(1, 8), 4, e->lna1_gain);
+       b43_ntab_write_bulk(dev, B43_NTAB8(0, 16), 4, e->lna2_gain);
+       b43_ntab_write_bulk(dev, B43_NTAB8(1, 16), 4, e->lna2_gain);
+       b43_ntab_write_bulk(dev, B43_NTAB8(0, 32), 10, e->gain_db);
+       b43_ntab_write_bulk(dev, B43_NTAB8(1, 32), 10, e->gain_db);
+       b43_ntab_write_bulk(dev, B43_NTAB8(2, 32), 10, e->gain_bits);
+       b43_ntab_write_bulk(dev, B43_NTAB8(3, 32), 10, e->gain_bits);
+       b43_ntab_write_bulk(dev, B43_NTAB8(0, 0x40), 6, lpf_gain);
+       b43_ntab_write_bulk(dev, B43_NTAB8(1, 0x40), 6, lpf_gain);
+       b43_ntab_write_bulk(dev, B43_NTAB8(2, 0x40), 6, lpf_bits);
+       b43_ntab_write_bulk(dev, B43_NTAB8(3, 0x40), 6, lpf_bits);
+       b43_phy_write(dev, B43_NPHY_C1_INITGAIN, e->init_gain);
+       b43_phy_write(dev, 0x2A7, e->init_gain);
+       b43_ntab_write_bulk(dev, B43_NTAB16(7, 0x106), 2,
+                               e->rfseq_init);
+       b43_phy_write(dev, B43_NPHY_C1_INITGAIN, e->init_gain);
+       /* TODO: check defines. Do not match variables names */
+       b43_phy_write(dev, B43_NPHY_C1_CLIP1_MEDGAIN, e->cliphi_gain);
+       b43_phy_write(dev, 0x2A9, e->cliphi_gain);
+       b43_phy_write(dev, B43_NPHY_C1_CLIP2_GAIN, e->clipmd_gain);
+       b43_phy_write(dev, 0x2AB, e->clipmd_gain);
+       b43_phy_write(dev, B43_NPHY_C2_CLIP1_HIGAIN, e->cliplo_gain);
+       b43_phy_write(dev, 0x2AD, e->cliplo_gain);
+       b43_phy_maskset(dev, 0x27D, 0xFF00, e->crsmin);
+       b43_phy_maskset(dev, 0x280, 0xFF00, e->crsminl);
+       b43_phy_maskset(dev, 0x283, 0xFF00, e->crsminu);
+       b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, e->nbclip);
+       b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, e->nbclip);
+       b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+                       ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, e->wlclip);
+       b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+                       ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, e->wlclip);
+       b43_phy_write(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
+ }
+ static void b43_nphy_gain_ctl_workarounds_rev1_2(struct b43_wldev *dev)
+ {
+       struct b43_phy_n *nphy = dev->phy.n;
+       u8 i, j;
+       u8 code;
+       u16 tmp;
+       u8 rfseq_events[3] = { 6, 8, 7 };
+       u8 rfseq_delays[3] = { 10, 30, 1 };
+       /* Set Clip 2 detect */
+       b43_phy_set(dev, B43_NPHY_C1_CGAINI, B43_NPHY_C1_CGAINI_CL2DETECT);
+       b43_phy_set(dev, B43_NPHY_C2_CGAINI, B43_NPHY_C2_CGAINI_CL2DETECT);
+       /* Set narrowband clip threshold */
+       b43_phy_write(dev, B43_NPHY_C1_NBCLIPTHRES, 0x84);
+       b43_phy_write(dev, B43_NPHY_C2_NBCLIPTHRES, 0x84);
+       if (!dev->phy.is_40mhz) {
+               /* Set dwell lengths */
+               b43_phy_write(dev, B43_NPHY_CLIP1_NBDWELL_LEN, 0x002B);
+               b43_phy_write(dev, B43_NPHY_CLIP2_NBDWELL_LEN, 0x002B);
+               b43_phy_write(dev, B43_NPHY_W1CLIP1_DWELL_LEN, 0x0009);
+               b43_phy_write(dev, B43_NPHY_W1CLIP2_DWELL_LEN, 0x0009);
+       }
+       /* Set wideband clip 2 threshold */
+       b43_phy_maskset(dev, B43_NPHY_C1_CLIPWBTHRES,
+                       ~B43_NPHY_C1_CLIPWBTHRES_CLIP2, 21);
+       b43_phy_maskset(dev, B43_NPHY_C2_CLIPWBTHRES,
+                       ~B43_NPHY_C2_CLIPWBTHRES_CLIP2, 21);
+       if (!dev->phy.is_40mhz) {
+               b43_phy_maskset(dev, B43_NPHY_C1_CGAINI,
+                       ~B43_NPHY_C1_CGAINI_GAINBKOFF, 0x1);
+               b43_phy_maskset(dev, B43_NPHY_C2_CGAINI,
+                       ~B43_NPHY_C2_CGAINI_GAINBKOFF, 0x1);
+               b43_phy_maskset(dev, B43_NPHY_C1_CCK_CGAINI,
+                       ~B43_NPHY_C1_CCK_CGAINI_GAINBKOFF, 0x1);
+               b43_phy_maskset(dev, B43_NPHY_C2_CCK_CGAINI,
+                       ~B43_NPHY_C2_CCK_CGAINI_GAINBKOFF, 0x1);
+       }
+       b43_phy_write(dev, B43_NPHY_CCK_SHIFTB_REF, 0x809C);
+       if (nphy->gain_boost) {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ &&
+                       dev->phy.is_40mhz)
+                       code = 4;
+               else
+                       code = 5;
+       } else {
+               code = dev->phy.is_40mhz ? 6 : 7;
+       }
+       /* Set HPVGA2 index */
+       b43_phy_maskset(dev, B43_NPHY_C1_INITGAIN, ~B43_NPHY_C1_INITGAIN_HPVGA2,
+                       code << B43_NPHY_C1_INITGAIN_HPVGA2_SHIFT);
+       b43_phy_maskset(dev, B43_NPHY_C2_INITGAIN, ~B43_NPHY_C2_INITGAIN_HPVGA2,
+                       code << B43_NPHY_C2_INITGAIN_HPVGA2_SHIFT);
+       b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
+       /* specs say about 2 loops, but wl does 4 */
+       for (i = 0; i < 4; i++)
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, (code << 8 | 0x7C));
+       b43_nphy_adjust_lna_gain_table(dev);
+       if (nphy->elna_gain_config) {
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0808);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x0C08);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x0);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+               b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0x1);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x1D06);
+               /* specs say about 2 loops, but wl does 4 */
+               for (i = 0; i < 4; i++)
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                               (code << 8 | 0x74));
+       }
+       if (dev->phy.rev == 2) {
+               for (i = 0; i < 4; i++) {
+                       b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+                                       (0x0400 * i) + 0x0020);
+                       for (j = 0; j < 21; j++) {
+                               tmp = j * (i < 2 ? 3 : 1);
+                               b43_phy_write(dev,
+                                       B43_NPHY_TABLE_DATALO, tmp);
+                       }
+               }
        }
+       b43_nphy_set_rf_sequence(dev, 5, rfseq_events, rfseq_delays, 3);
+       b43_phy_maskset(dev, B43_NPHY_OVER_DGAIN1,
+               ~B43_NPHY_OVER_DGAIN_CCKDGECV & 0xFFFF,
+               0x5A << B43_NPHY_OVER_DGAIN_CCKDGECV_SHIFT);
+       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+               b43_phy_maskset(dev, B43_PHY_N(0xC5D), 0xFF80, 4);
+ }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/WorkaroundsGainCtrl */
+ static void b43_nphy_gain_ctl_workarounds(struct b43_wldev *dev)
+ {
+       if (dev->phy.rev >= 3)
+               b43_nphy_gain_ctl_workarounds_rev3plus(dev);
+       else
+               b43_nphy_gain_ctl_workarounds_rev1_2(dev);
  }
  
  static void b43_nphy_workarounds_rev3plus(struct b43_wldev *dev)
        b43_ntab_write(dev, B43_NTAB32(16, 3), 0x18D);
        b43_ntab_write(dev, B43_NTAB32(16, 127), 0x18D);
  
-       b43_nphy_gain_ctrl_workarounds(dev);
+       b43_nphy_gain_ctl_workarounds(dev);
  
        b43_ntab_write(dev, B43_NTAB16(8, 0), 2);
        b43_ntab_write(dev, B43_NTAB16(8, 16), 2);
@@@ -1763,7 -1868,7 +1868,7 @@@ static void b43_nphy_workarounds_rev1_2
        b43_nphy_set_rf_sequence(dev, 0, events1, delays1, 7);
        b43_nphy_set_rf_sequence(dev, 1, events2, delays2, 7);
  
-       b43_nphy_gain_ctrl_workarounds(dev);
+       b43_nphy_gain_ctl_workarounds(dev);
  
        if (dev->phy.rev < 2) {
                if (b43_phy_read(dev, B43_NPHY_RXCTL) & 0x2)
@@@ -1823,984 -1928,811 +1928,811 @@@ static void b43_nphy_workarounds(struc
                b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/LoadSampleTable */
- static int b43_nphy_load_samples(struct b43_wldev *dev,
-                                       struct b43_c32 *samples, u16 len) {
-       struct b43_phy_n *nphy = dev->phy.n;
-       u16 i;
-       u32 *data;
-       data = kzalloc(len * sizeof(u32), GFP_KERNEL);
-       if (!data) {
-               b43err(dev->wl, "allocation for samples loading failed\n");
-               return -ENOMEM;
-       }
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 1);
+ /**************************************************
+  * Tx and Rx
+  **************************************************/
  
-       for (i = 0; i < len; i++) {
-               data[i] = (samples[i].i & 0x3FF << 10);
-               data[i] |= samples[i].q & 0x3FF;
-       }
-       b43_ntab_write_bulk(dev, B43_NTAB32(17, 0), len, data);
-       kfree(data);
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, 0);
-       return 0;
+ void b43_nphy_set_rxantenna(struct b43_wldev *dev, int antenna)
+ {//TODO
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GenLoadSamples */
- static u16 b43_nphy_gen_load_samples(struct b43_wldev *dev, u32 freq, u16 max,
-                                       bool test)
- {
-       int i;
-       u16 bw, len, rot, angle;
-       struct b43_c32 *samples;
+ static void b43_nphy_op_adjust_txpower(struct b43_wldev *dev)
+ {//TODO
+ }
  
-       bw = (dev->phy.is_40mhz) ? 40 : 20;
-       len = bw << 3;
+ static enum b43_txpwr_result b43_nphy_op_recalc_txpower(struct b43_wldev *dev,
+                                                       bool ignore_tssi)
+ {//TODO
+       return B43_TXPWR_RES_DONE;
+ }
  
-       if (test) {
-               if (b43_phy_read(dev, B43_NPHY_BBCFG) & B43_NPHY_BBCFG_RSTRX)
-                       bw = 82;
-               else
-                       bw = 80;
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlEnable */
+ static void b43_nphy_tx_power_ctrl(struct b43_wldev *dev, bool enable)
+ {
+       struct b43_phy_n *nphy = dev->phy.n;
+       u8 i;
+       u16 bmask, val, tmp;
+       enum ieee80211_band band = b43_current_band(dev->wl);
  
-               if (dev->phy.is_40mhz)
-                       bw <<= 1;
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
  
-               len = bw << 1;
-       }
+       nphy->txpwrctrl = enable;
+       if (!enable) {
+               if (dev->phy.rev >= 3 &&
+                   (b43_phy_read(dev, B43_NPHY_TXPCTL_CMD) &
+                    (B43_NPHY_TXPCTL_CMD_COEFF |
+                     B43_NPHY_TXPCTL_CMD_HWPCTLEN |
+                     B43_NPHY_TXPCTL_CMD_PCTLEN))) {
+                       /* We disable enabled TX pwr ctl, save it's state */
+                       nphy->tx_pwr_idx[0] = b43_phy_read(dev,
+                                               B43_NPHY_C1_TXPCTL_STAT) & 0x7f;
+                       nphy->tx_pwr_idx[1] = b43_phy_read(dev,
+                                               B43_NPHY_C2_TXPCTL_STAT) & 0x7f;
+               }
  
-       samples = kcalloc(len, sizeof(struct b43_c32), GFP_KERNEL);
-       if (!samples) {
-               b43err(dev->wl, "allocation for samples generation failed\n");
-               return 0;
-       }
-       rot = (((freq * 36) / bw) << 16) / 100;
-       angle = 0;
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6840);
+               for (i = 0; i < 84; i++)
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0);
  
-       for (i = 0; i < len; i++) {
-               samples[i] = b43_cordic(angle);
-               angle += rot;
-               samples[i].q = CORDIC_CONVERT(samples[i].q * max);
-               samples[i].i = CORDIC_CONVERT(samples[i].i * max);
-       }
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR, 0x6C40);
+               for (i = 0; i < 84; i++)
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO, 0);
  
-       i = b43_nphy_load_samples(dev, samples, len);
-       kfree(samples);
-       return (i < 0) ? 0 : len;
- }
+               tmp = B43_NPHY_TXPCTL_CMD_COEFF | B43_NPHY_TXPCTL_CMD_HWPCTLEN;
+               if (dev->phy.rev >= 3)
+                       tmp |= B43_NPHY_TXPCTL_CMD_PCTLEN;
+               b43_phy_mask(dev, B43_NPHY_TXPCTL_CMD, ~tmp);
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RunSamples */
- static void b43_nphy_run_samples(struct b43_wldev *dev, u16 samps, u16 loops,
-                                       u16 wait, bool iqmode, bool dac_test)
- {
-       struct b43_phy_n *nphy = dev->phy.n;
-       int i;
-       u16 seq_mode;
-       u32 tmp;
+               if (dev->phy.rev >= 3) {
+                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0100);
+                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0100);
+               } else {
+                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4000);
+               }
  
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, true);
+               if (dev->phy.rev == 2)
+                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+                               ~B43_NPHY_BPHY_CTL3_SCALE, 0x53);
+               else if (dev->phy.rev < 2)
+                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3,
+                               ~B43_NPHY_BPHY_CTL3_SCALE, 0x5A);
  
-       if ((nphy->bb_mult_save & 0x80000000) == 0) {
-               tmp = b43_ntab_read(dev, B43_NTAB16(15, 87));
-               nphy->bb_mult_save = (tmp & 0xFFFF) | 0x80000000;
-       }
+               if (dev->phy.rev < 2 && dev->phy.is_40mhz)
+                       b43_hf_write(dev, b43_hf_read(dev) | B43_HF_TSSIRPSMW);
+       } else {
+               b43_ntab_write_bulk(dev, B43_NTAB16(26, 64), 84,
+                                   nphy->adj_pwr_tbl);
+               b43_ntab_write_bulk(dev, B43_NTAB16(27, 64), 84,
+                                   nphy->adj_pwr_tbl);
  
-       if (!dev->phy.is_40mhz)
-               tmp = 0x6464;
-       else
-               tmp = 0x4747;
-       b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
+               bmask = B43_NPHY_TXPCTL_CMD_COEFF |
+                       B43_NPHY_TXPCTL_CMD_HWPCTLEN;
+               /* wl does useless check for "enable" param here */
+               val = B43_NPHY_TXPCTL_CMD_COEFF | B43_NPHY_TXPCTL_CMD_HWPCTLEN;
+               if (dev->phy.rev >= 3) {
+                       bmask |= B43_NPHY_TXPCTL_CMD_PCTLEN;
+                       if (val)
+                               val |= B43_NPHY_TXPCTL_CMD_PCTLEN;
+               }
+               b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD, ~(bmask), val);
  
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, false);
+               if (band == IEEE80211_BAND_5GHZ) {
+                       b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
+                                       ~B43_NPHY_TXPCTL_CMD_INIT, 0x64);
+                       if (dev->phy.rev > 1)
+                               b43_phy_maskset(dev, B43_NPHY_TXPCTL_INIT,
+                                               ~B43_NPHY_TXPCTL_INIT_PIDXI1,
+                                               0x64);
+               }
  
-       b43_phy_write(dev, B43_NPHY_SAMP_DEPCNT, (samps - 1));
+               if (dev->phy.rev >= 3) {
+                       if (nphy->tx_pwr_idx[0] != 128 &&
+                           nphy->tx_pwr_idx[1] != 128) {
+                               /* Recover TX pwr ctl state */
+                               b43_phy_maskset(dev, B43_NPHY_TXPCTL_CMD,
+                                               ~B43_NPHY_TXPCTL_CMD_INIT,
+                                               nphy->tx_pwr_idx[0]);
+                               if (dev->phy.rev > 1)
+                                       b43_phy_maskset(dev,
+                                               B43_NPHY_TXPCTL_INIT,
+                                               ~0xff, nphy->tx_pwr_idx[1]);
+                       }
+               }
  
-       if (loops != 0xFFFF)
-               b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, (loops - 1));
-       else
-               b43_phy_write(dev, B43_NPHY_SAMP_LOOPCNT, loops);
+               if (dev->phy.rev >= 3) {
+                       b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, ~0x100);
+                       b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x100);
+               } else {
+                       b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x4000);
+               }
  
-       b43_phy_write(dev, B43_NPHY_SAMP_WAITCNT, wait);
+               if (dev->phy.rev == 2)
+                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x3b);
+               else if (dev->phy.rev < 2)
+                       b43_phy_maskset(dev, B43_NPHY_BPHY_CTL3, ~0xFF, 0x40);
  
-       seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
+               if (dev->phy.rev < 2 && dev->phy.is_40mhz)
+                       b43_hf_write(dev, b43_hf_read(dev) & ~B43_HF_TSSIRPSMW);
  
-       b43_phy_set(dev, B43_NPHY_RFSEQMODE, B43_NPHY_RFSEQMODE_CAOVER);
-       if (iqmode) {
-               b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
-               b43_phy_set(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x8000);
-       } else {
-               if (dac_test)
-                       b43_phy_write(dev, B43_NPHY_SAMP_CMD, 5);
-               else
-                       b43_phy_write(dev, B43_NPHY_SAMP_CMD, 1);
-       }
-       for (i = 0; i < 100; i++) {
-               if (b43_phy_read(dev, B43_NPHY_RFSEQST) & 1) {
-                       i = 0;
-                       break;
+               if (b43_nphy_ipa(dev)) {
+                       b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x4);
+                       b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x4);
                }
-               udelay(10);
        }
-       if (i)
-               b43err(dev->wl, "run samples timeout\n");
-       b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
- }
  
- /*
-  * Transmits a known value for LO calibration
-  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
-  */
- static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
-                               bool iqmode, bool dac_test)
- {
-       u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
-       if (samp == 0)
-               return -1;
-       b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
-       return 0;
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
- static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrFix */
+ static void b43_nphy_tx_power_fix(struct b43_wldev *dev)
  {
        struct b43_phy_n *nphy = dev->phy.n;
-       int i, j;
-       u32 tmp;
-       u32 cur_real, cur_imag, real_part, imag_part;
+       struct ssb_sprom *sprom = dev->dev->bus_sprom;
  
-       u16 buffer[7];
+       u8 txpi[2], bbmult, i;
+       u16 tmp, radio_gain, dac_gain;
+       u16 freq = dev->phy.channel_freq;
+       u32 txgain;
+       /* u32 gaintbl; rev3+ */
  
        if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, true);
-       b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
-       for (i = 0; i < 2; i++) {
-               tmp = ((buffer[i * 2] & 0x3FF) << 10) |
-                       (buffer[i * 2 + 1] & 0x3FF);
-               b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
-                               (((i + 26) << 10) | 320));
-               for (j = 0; j < 128; j++) {
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
-                                       ((tmp >> 16) & 0xFFFF));
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
-                                       (tmp & 0xFFFF));
-               }
-       }
-       for (i = 0; i < 2; i++) {
-               tmp = buffer[5 + i];
-               real_part = (tmp >> 8) & 0xFF;
-               imag_part = (tmp & 0xFF);
-               b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
-                               (((i + 26) << 10) | 448));
+               b43_nphy_stay_in_carrier_search(dev, 1);
  
-               if (dev->phy.rev >= 3) {
-                       cur_real = real_part;
-                       cur_imag = imag_part;
-                       tmp = ((cur_real & 0xFF) << 8) | (cur_imag & 0xFF);
-               }
-               for (j = 0; j < 128; j++) {
-                       if (dev->phy.rev < 3) {
-                               cur_real = (real_part * loscale[j] + 128) >> 8;
-                               cur_imag = (imag_part * loscale[j] + 128) >> 8;
-                               tmp = ((cur_real & 0xFF) << 8) |
-                                       (cur_imag & 0xFF);
-                       }
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
-                                       ((tmp >> 16) & 0xFFFF));
-                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
-                                       (tmp & 0xFFFF));
+       if (dev->phy.rev >= 7) {
+               txpi[0] = txpi[1] = 30;
+       } else if (dev->phy.rev >= 3) {
+               txpi[0] = 40;
+               txpi[1] = 40;
+       } else if (sprom->revision < 4) {
+               txpi[0] = 72;
+               txpi[1] = 72;
+       } else {
+               if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
+                       txpi[0] = sprom->txpid2g[0];
+                       txpi[1] = sprom->txpid2g[1];
+               } else if (freq >= 4900 && freq < 5100) {
+                       txpi[0] = sprom->txpid5gl[0];
+                       txpi[1] = sprom->txpid5gl[1];
+               } else if (freq >= 5100 && freq < 5500) {
+                       txpi[0] = sprom->txpid5g[0];
+                       txpi[1] = sprom->txpid5g[1];
+               } else if (freq >= 5500) {
+                       txpi[0] = sprom->txpid5gh[0];
+                       txpi[1] = sprom->txpid5gh[1];
+               } else {
+                       txpi[0] = 91;
+                       txpi[1] = 91;
                }
        }
+       if (dev->phy.rev < 7 &&
+           (txpi[0] < 40 || txpi[0] > 100 || txpi[1] < 40 || txpi[1] > 10))
+               txpi[0] = txpi[1] = 91;
  
-       if (dev->phy.rev >= 3) {
-               b43_shm_write16(dev, B43_SHM_SHARED,
-                               B43_SHM_SH_NPHY_TXPWR_INDX0, 0xFFFF);
-               b43_shm_write16(dev, B43_SHM_SHARED,
-                               B43_SHM_SH_NPHY_TXPWR_INDX1, 0xFFFF);
-       }
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, false);
- }
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRfSeq */
- static void b43_nphy_set_rf_sequence(struct b43_wldev *dev, u8 cmd,
-                                       u8 *events, u8 *delays, u8 length)
- {
-       struct b43_phy_n *nphy = dev->phy.n;
-       u8 i;
-       u8 end = (dev->phy.rev >= 3) ? 0x1F : 0x0F;
-       u16 offset1 = cmd << 4;
-       u16 offset2 = offset1 + 0x80;
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, true);
-       b43_ntab_write_bulk(dev, B43_NTAB8(7, offset1), length, events);
-       b43_ntab_write_bulk(dev, B43_NTAB8(7, offset2), length, delays);
-       for (i = length; i < 16; i++) {
-               b43_ntab_write(dev, B43_NTAB8(7, offset1 + i), end);
-               b43_ntab_write(dev, B43_NTAB8(7, offset2 + i), 1);
-       }
-       if (nphy->hang_avoid)
-               b43_nphy_stay_in_carrier_search(dev, false);
- }
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ForceRFSeq */
- static void b43_nphy_force_rf_sequence(struct b43_wldev *dev,
-                                      enum b43_nphy_rf_sequence seq)
- {
-       static const u16 trigger[] = {
-               [B43_RFSEQ_RX2TX]               = B43_NPHY_RFSEQTR_RX2TX,
-               [B43_RFSEQ_TX2RX]               = B43_NPHY_RFSEQTR_TX2RX,
-               [B43_RFSEQ_RESET2RX]            = B43_NPHY_RFSEQTR_RST2RX,
-               [B43_RFSEQ_UPDATE_GAINH]        = B43_NPHY_RFSEQTR_UPGH,
-               [B43_RFSEQ_UPDATE_GAINL]        = B43_NPHY_RFSEQTR_UPGL,
-               [B43_RFSEQ_UPDATE_GAINU]        = B43_NPHY_RFSEQTR_UPGU,
-       };
-       int i;
-       u16 seq_mode = b43_phy_read(dev, B43_NPHY_RFSEQMODE);
-       B43_WARN_ON(seq >= ARRAY_SIZE(trigger));
-       b43_phy_set(dev, B43_NPHY_RFSEQMODE,
-                   B43_NPHY_RFSEQMODE_CAOVER | B43_NPHY_RFSEQMODE_TROVER);
-       b43_phy_set(dev, B43_NPHY_RFSEQTR, trigger[seq]);
-       for (i = 0; i < 200; i++) {
-               if (!(b43_phy_read(dev, B43_NPHY_RFSEQST) & trigger[seq]))
-                       goto ok;
-               msleep(1);
+       /*
+       for (i = 0; i < 2; i++) {
+               nphy->txpwrindex[i].index_internal = txpi[i];
+               nphy->txpwrindex[i].index_internal_save = txpi[i];
        }
-       b43err(dev->wl, "RF sequence status timeout\n");
- ok:
-       b43_phy_write(dev, B43_NPHY_RFSEQMODE, seq_mode);
- }
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlOverride */
- static void b43_nphy_rf_control_override(struct b43_wldev *dev, u16 field,
-                                               u16 value, u8 core, bool off)
- {
-       int i;
-       u8 index = fls(field);
-       u8 addr, en_addr, val_addr;
-       /* we expect only one bit set */
-       B43_WARN_ON(field & (~(1 << (index - 1))));
-       if (dev->phy.rev >= 3) {
-               const struct nphy_rf_control_override_rev3 *rf_ctrl;
-               for (i = 0; i < 2; i++) {
-                       if (index == 0 || index == 16) {
-                               b43err(dev->wl,
-                                       "Unsupported RF Ctrl Override call\n");
-                               return;
-                       }
-                       rf_ctrl = &tbl_rf_control_override_rev3[index - 1];
-                       en_addr = B43_PHY_N((i == 0) ?
-                               rf_ctrl->en_addr0 : rf_ctrl->en_addr1);
-                       val_addr = B43_PHY_N((i == 0) ?
-                               rf_ctrl->val_addr0 : rf_ctrl->val_addr1);
+       */
  
-                       if (off) {
-                               b43_phy_mask(dev, en_addr, ~(field));
-                               b43_phy_mask(dev, val_addr,
-                                               ~(rf_ctrl->val_mask));
+       for (i = 0; i < 2; i++) {
+               if (dev->phy.rev >= 3) {
+                       if (b43_nphy_ipa(dev)) {
+                               txgain = *(b43_nphy_get_ipa_gain_table(dev) +
+                                               txpi[i]);
+                       } else if (b43_current_band(dev->wl) ==
+                                  IEEE80211_BAND_5GHZ) {
+                               /* FIXME: use 5GHz tables */
+                               txgain =
+                                       b43_ntab_tx_gain_rev3plus_2ghz[txpi[i]];
                        } else {
-                               if (core == 0 || ((1 << core) & i) != 0) {
-                                       b43_phy_set(dev, en_addr, field);
-                                       b43_phy_maskset(dev, val_addr,
-                                               ~(rf_ctrl->val_mask),
-                                               (value << rf_ctrl->val_shift));
-                               }
+                               if (dev->phy.rev >= 5 &&
+                                   sprom->fem.ghz5.extpa_gain == 3)
+                                       ; /* FIXME: 5GHz_txgain_HiPwrEPA */
+                               txgain =
+                                       b43_ntab_tx_gain_rev3plus_2ghz[txpi[i]];
                        }
-               }
-       } else {
-               const struct nphy_rf_control_override_rev2 *rf_ctrl;
-               if (off) {
-                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~(field));
-                       value = 0;
+                       radio_gain = (txgain >> 16) & 0x1FFFF;
                } else {
-                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER, field);
+                       txgain = b43_ntab_tx_gain_rev0_1_2[txpi[i]];
+                       radio_gain = (txgain >> 16) & 0x1FFF;
                }
  
-               for (i = 0; i < 2; i++) {
-                       if (index <= 1 || index == 16) {
-                               b43err(dev->wl,
-                                       "Unsupported RF Ctrl Override call\n");
-                               return;
-                       }
+               if (dev->phy.rev >= 7)
+                       dac_gain = (txgain >> 8) & 0x7;
+               else
+                       dac_gain = (txgain >> 8) & 0x3F;
+               bbmult = txgain & 0xFF;
  
-                       if (index == 2 || index == 10 ||
-                           (index >= 13 && index <= 15)) {
-                               core = 1;
-                       }
+               if (dev->phy.rev >= 3) {
+                       if (i == 0)
+                               b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0100);
+                       else
+                               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0100);
+               } else {
+                       b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x4000);
+               }
  
-                       rf_ctrl = &tbl_rf_control_override_rev2[index - 2];
-                       addr = B43_PHY_N((i == 0) ?
-                               rf_ctrl->addr0 : rf_ctrl->addr1);
+               if (i == 0)
+                       b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN1, dac_gain);
+               else
+                       b43_phy_write(dev, B43_NPHY_AFECTL_DACGAIN2, dac_gain);
  
-                       if ((core & (1 << i)) != 0)
-                               b43_phy_maskset(dev, addr, ~(rf_ctrl->bmask),
-                                               (value << rf_ctrl->shift));
+               b43_ntab_write(dev, B43_NTAB16(0x7, 0x110 + i), radio_gain);
  
-                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER, 0x1);
-                       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
-                                       B43_NPHY_RFCTL_CMD_START);
-                       udelay(1);
-                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, 0xFFFE);
+               tmp = b43_ntab_read(dev, B43_NTAB16(0xF, 0x57));
+               if (i == 0)
+                       tmp = (tmp & 0x00FF) | (bbmult << 8);
+               else
+                       tmp = (tmp & 0xFF00) | bbmult;
+               b43_ntab_write(dev, B43_NTAB16(0xF, 0x57), tmp);
+               if (b43_nphy_ipa(dev)) {
+                       u32 tmp32;
+                       u16 reg = (i == 0) ?
+                               B43_NPHY_PAPD_EN0 : B43_NPHY_PAPD_EN1;
+                       tmp32 = b43_ntab_read(dev, B43_NTAB32(26 + i,
+                                                             576 + txpi[i]));
+                       b43_phy_maskset(dev, reg, 0xE00F, (u32) tmp32 << 4);
+                       b43_phy_set(dev, reg, 0x4);
                }
        }
- }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RFCtrlIntcOverride */
- static void b43_nphy_rf_control_intc_override(struct b43_wldev *dev, u8 field,
-                                               u16 value, u8 core)
- {
-       u8 i, j;
-       u16 reg, tmp, val;
-       B43_WARN_ON(dev->phy.rev < 3);
-       B43_WARN_ON(field > 4);
+       b43_phy_mask(dev, B43_NPHY_BPHY_CTL2, ~B43_NPHY_BPHY_CTL2_LUT);
  
-       for (i = 0; i < 2; i++) {
-               if ((core == 1 && i == 1) || (core == 2 && !i))
-                       continue;
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+ }
  
-               reg = (i == 0) ?
-                       B43_NPHY_RFCTL_INTC1 : B43_NPHY_RFCTL_INTC2;
-               b43_phy_mask(dev, reg, 0xFBFF);
+ static void b43_nphy_tx_gain_table_upload(struct b43_wldev *dev)
+ {
+       struct b43_phy *phy = &dev->phy;
  
-               switch (field) {
-               case 0:
-                       b43_phy_write(dev, reg, 0);
-                       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RESET2RX);
-                       break;
-               case 1:
-                       if (!i) {
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC1,
-                                               0xFC3F, (value << 6));
-                               b43_phy_maskset(dev, B43_NPHY_TXF_40CO_B1S1,
-                                               0xFFFE, 1);
-                               b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
-                                               B43_NPHY_RFCTL_CMD_START);
-                               for (j = 0; j < 100; j++) {
-                                       if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_START) {
-                                               j = 0;
-                                               break;
-                                       }
-                                       udelay(10);
-                               }
-                               if (j)
-                                       b43err(dev->wl,
-                                               "intc override timeout\n");
-                               b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S1,
-                                               0xFFFE);
-                       } else {
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_INTC2,
-                                               0xFC3F, (value << 6));
-                               b43_phy_maskset(dev, B43_NPHY_RFCTL_OVER,
-                                               0xFFFE, 1);
-                               b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
-                                               B43_NPHY_RFCTL_CMD_RXTX);
-                               for (j = 0; j < 100; j++) {
-                                       if (b43_phy_read(dev, B43_NPHY_RFCTL_CMD) & B43_NPHY_RFCTL_CMD_RXTX) {
-                                               j = 0;
-                                               break;
-                                       }
-                                       udelay(10);
-                               }
-                               if (j)
-                                       b43err(dev->wl,
-                                               "intc override timeout\n");
-                               b43_phy_mask(dev, B43_NPHY_RFCTL_OVER,
-                                               0xFFFE);
-                       }
-                       break;
-               case 2:
-                       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
-                               tmp = 0x0020;
-                               val = value << 5;
-                       } else {
-                               tmp = 0x0010;
-                               val = value << 4;
-                       }
-                       b43_phy_maskset(dev, reg, ~tmp, val);
-                       break;
-               case 3:
-                       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
-                               tmp = 0x0001;
-                               val = value;
-                       } else {
-                               tmp = 0x0004;
-                               val = value << 2;
-                       }
-                       b43_phy_maskset(dev, reg, ~tmp, val);
-                       break;
-               case 4:
+       const u32 *table = NULL;
+ #if 0
+       TODO: b43_ntab_papd_pga_gain_delta_ipa_2*
+       u32 rfpwr_offset;
+       u8 pga_gain;
+       int i;
+ #endif
+       if (phy->rev >= 3) {
+               if (b43_nphy_ipa(dev)) {
+                       table = b43_nphy_get_ipa_gain_table(dev);
+               } else {
                        if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) {
-                               tmp = 0x0002;
-                               val = value << 1;
+                               if (phy->rev == 3)
+                                       table = b43_ntab_tx_gain_rev3_5ghz;
+                               if (phy->rev == 4)
+                                       table = b43_ntab_tx_gain_rev4_5ghz;
+                               else
+                                       table = b43_ntab_tx_gain_rev5plus_5ghz;
                        } else {
-                               tmp = 0x0008;
-                               val = value << 3;
+                               table = b43_ntab_tx_gain_rev3plus_2ghz;
                        }
-                       b43_phy_maskset(dev, reg, ~tmp, val);
-                       break;
                }
+       } else {
+               table = b43_ntab_tx_gain_rev0_1_2;
+       }
+       b43_ntab_write_bulk(dev, B43_NTAB32(26, 192), 128, table);
+       b43_ntab_write_bulk(dev, B43_NTAB32(27, 192), 128, table);
+       if (phy->rev >= 3) {
+ #if 0
+               nphy->gmval = (table[0] >> 16) & 0x7000;
+               for (i = 0; i < 128; i++) {
+                       pga_gain = (table[i] >> 24) & 0xF;
+                       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ)
+                               rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_2g[pga_gain];
+                       else
+                               rfpwr_offset = b43_ntab_papd_pga_gain_delta_ipa_5g[pga_gain];
+                       b43_ntab_write(dev, B43_NTAB32(26, 576 + i),
+                                      rfpwr_offset);
+                       b43_ntab_write(dev, B43_NTAB32(27, 576 + i),
+                                      rfpwr_offset);
+               }
+ #endif
        }
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */
- static void b43_nphy_bphy_init(struct b43_wldev *dev)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PA%20override */
+ static void b43_nphy_pa_override(struct b43_wldev *dev, bool enable)
  {
-       unsigned int i;
-       u16 val;
+       struct b43_phy_n *nphy = dev->phy.n;
+       enum ieee80211_band band;
+       u16 tmp;
  
-       val = 0x1E1F;
-       for (i = 0; i < 16; i++) {
-               b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
-               val -= 0x202;
-       }
-       val = 0x3E3F;
-       for (i = 0; i < 16; i++) {
-               b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val);
-               val -= 0x202;
+       if (!enable) {
+               nphy->rfctrl_intc1_save = b43_phy_read(dev,
+                                                      B43_NPHY_RFCTL_INTC1);
+               nphy->rfctrl_intc2_save = b43_phy_read(dev,
+                                                      B43_NPHY_RFCTL_INTC2);
+               band = b43_current_band(dev->wl);
+               if (dev->phy.rev >= 3) {
+                       if (band == IEEE80211_BAND_5GHZ)
+                               tmp = 0x600;
+                       else
+                               tmp = 0x480;
+               } else {
+                       if (band == IEEE80211_BAND_5GHZ)
+                               tmp = 0x180;
+                       else
+                               tmp = 0x120;
+               }
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, tmp);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, tmp);
+       } else {
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC1,
+                               nphy->rfctrl_intc1_save);
+               b43_phy_write(dev, B43_NPHY_RFCTL_INTC2,
+                               nphy->rfctrl_intc2_save);
        }
-       b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/ScaleOffsetRssi */
- static void b43_nphy_scale_offset_rssi(struct b43_wldev *dev, u16 scale,
-                                       s8 offset, u8 core, u8 rail,
-                                       enum b43_nphy_rssi_type type)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxLpFbw */
+ static void b43_nphy_tx_lp_fbw(struct b43_wldev *dev)
  {
        u16 tmp;
-       bool core1or5 = (core == 1) || (core == 5);
-       bool core2or5 = (core == 2) || (core == 5);
-       offset = clamp_val(offset, -32, 31);
-       tmp = ((scale & 0x3F) << 8) | (offset & 0x3F);
  
-       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Z, tmp);
-       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Z, tmp);
-       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Z))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Z, tmp);
-       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Z))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Z, tmp);
+       if (dev->phy.rev >= 3) {
+               if (b43_nphy_ipa(dev)) {
+                       tmp = 4;
+                       b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S2,
+                             (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
+               }
  
-       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_X, tmp);
-       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_X, tmp);
-       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_X))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_X, tmp);
-       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_X))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_X, tmp);
+               tmp = 1;
+               b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S2,
+                             (((((tmp << 3) | tmp) << 3) | tmp) << 3) | tmp);
+       }
+ }
  
-       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_RSSI_Y, tmp);
-       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_RSSI_Y, tmp);
-       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_Y))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_RSSI_Y, tmp);
-       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_Y))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, tmp);
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/Chains */
+ static void b43_nphy_update_txrx_chain(struct b43_wldev *dev)
+ {
+       struct b43_phy_n *nphy = dev->phy.n;
  
-       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TBD, tmp);
-       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TBD, tmp);
-       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_TBD))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TBD, tmp);
-       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_TBD))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TBD, tmp);
+       bool override = false;
+       u16 chain = 0x33;
  
-       if (core1or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_PWRDET, tmp);
-       if (core1or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_PWRDET, tmp);
-       if (core2or5 && (rail == 0) && (type == B43_NPHY_RSSI_PWRDET))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_PWRDET, tmp);
-       if (core2or5 && (rail == 1) && (type == B43_NPHY_RSSI_PWRDET))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_PWRDET, tmp);
+       if (nphy->txrx_chain == 0) {
+               chain = 0x11;
+               override = true;
+       } else if (nphy->txrx_chain == 1) {
+               chain = 0x22;
+               override = true;
+       }
  
-       if (core1or5 && (type == B43_NPHY_RSSI_TSSI_I))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0I_TSSI, tmp);
-       if (core2or5 && (type == B43_NPHY_RSSI_TSSI_I))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1I_TSSI, tmp);
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
+                       ~(B43_NPHY_RFSEQCA_TXEN | B43_NPHY_RFSEQCA_RXEN),
+                       chain);
  
-       if (core1or5 && (type == B43_NPHY_RSSI_TSSI_Q))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_0Q_TSSI, tmp);
-       if (core2or5 && (type == B43_NPHY_RSSI_TSSI_Q))
-               b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_TSSI, tmp);
+       if (override)
+               b43_phy_set(dev, B43_NPHY_RFSEQMODE,
+                               B43_NPHY_RFSEQMODE_CAOVER);
+       else
+               b43_phy_mask(dev, B43_NPHY_RFSEQMODE,
+                               ~B43_NPHY_RFSEQMODE_CAOVER);
  }
  
- static void b43_nphy_rev2_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqEst */
+ static void b43_nphy_rx_iq_est(struct b43_wldev *dev, struct nphy_iq_est *est,
+                               u16 samps, u8 time, bool wait)
  {
-       u16 val;
+       int i;
+       u16 tmp;
  
-       if (type < 3)
-               val = 0;
-       else if (type == 6)
-               val = 1;
-       else if (type == 3)
-               val = 2;
+       b43_phy_write(dev, B43_NPHY_IQEST_SAMCNT, samps);
+       b43_phy_maskset(dev, B43_NPHY_IQEST_WT, ~B43_NPHY_IQEST_WT_VAL, time);
+       if (wait)
+               b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_MODE);
        else
-               val = 3;
+               b43_phy_mask(dev, B43_NPHY_IQEST_CMD, ~B43_NPHY_IQEST_CMD_MODE);
  
-       val = (val << 12) | (val << 14);
-       b43_phy_maskset(dev, B43_NPHY_AFECTL_C1, 0x0FFF, val);
-       b43_phy_maskset(dev, B43_NPHY_AFECTL_C2, 0x0FFF, val);
+       b43_phy_set(dev, B43_NPHY_IQEST_CMD, B43_NPHY_IQEST_CMD_START);
  
-       if (type < 3) {
-               b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO1, 0xFFCF,
-                               (type + 1) << 4);
-               b43_phy_maskset(dev, B43_NPHY_RFCTL_RSSIO2, 0xFFCF,
-                               (type + 1) << 4);
-       }
+       for (i = 1000; i; i--) {
+               tmp = b43_phy_read(dev, B43_NPHY_IQEST_CMD);
+               if (!(tmp & B43_NPHY_IQEST_CMD_START)) {
+                       est->i0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI0) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO0);
+                       est->q0_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI0) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO0);
+                       est->iq0_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI0) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO0);
  
-       if (code == 0) {
-               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, ~0x3000);
-               if (type < 3) {
-                       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
-                               ~(B43_NPHY_RFCTL_CMD_RXEN |
-                                 B43_NPHY_RFCTL_CMD_CORESEL));
-                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER,
-                               ~(0x1 << 12 |
-                                 0x1 << 5 |
-                                 0x1 << 1 |
-                                 0x1));
-                       b43_phy_mask(dev, B43_NPHY_RFCTL_CMD,
-                               ~B43_NPHY_RFCTL_CMD_START);
-                       udelay(20);
-                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
-               }
-       } else {
-               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x3000);
-               if (type < 3) {
-                       b43_phy_maskset(dev, B43_NPHY_RFCTL_CMD,
-                               ~(B43_NPHY_RFCTL_CMD_RXEN |
-                                 B43_NPHY_RFCTL_CMD_CORESEL),
-                               (B43_NPHY_RFCTL_CMD_RXEN |
-                                code << B43_NPHY_RFCTL_CMD_CORESEL_SHIFT));
-                       b43_phy_set(dev, B43_NPHY_RFCTL_OVER,
-                               (0x1 << 12 |
-                                 0x1 << 5 |
-                                 0x1 << 1 |
-                                 0x1));
-                       b43_phy_set(dev, B43_NPHY_RFCTL_CMD,
-                               B43_NPHY_RFCTL_CMD_START);
-                       udelay(20);
-                       b43_phy_mask(dev, B43_NPHY_RFCTL_OVER, ~0x1);
+                       est->i1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_IPACC_HI1) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_IPACC_LO1);
+                       est->q1_pwr = (b43_phy_read(dev, B43_NPHY_IQEST_QPACC_HI1) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_QPACC_LO1);
+                       est->iq1_prod = (b43_phy_read(dev, B43_NPHY_IQEST_IQACC_HI1) << 16) |
+                                       b43_phy_read(dev, B43_NPHY_IQEST_IQACC_LO1);
+                       return;
                }
+               udelay(10);
        }
+       memset(est, 0, sizeof(*est));
  }
  
- static void b43_nphy_rev3_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxIqCoeffs */
+ static void b43_nphy_rx_iq_coeffs(struct b43_wldev *dev, bool write,
+                                       struct b43_phy_n_iq_comp *pcomp)
  {
-       u8 i;
-       u16 reg, val;
-       if (code == 0) {
-               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER1, 0xFDFF);
-               b43_phy_mask(dev, B43_NPHY_AFECTL_OVER, 0xFDFF);
-               b43_phy_mask(dev, B43_NPHY_AFECTL_C1, 0xFCFF);
-               b43_phy_mask(dev, B43_NPHY_AFECTL_C2, 0xFCFF);
-               b43_phy_mask(dev, B43_NPHY_TXF_40CO_B1S0, 0xFFDF);
-               b43_phy_mask(dev, B43_NPHY_TXF_40CO_B32S1, 0xFFDF);
-               b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0xFFC3);
-               b43_phy_mask(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0xFFC3);
+       if (write) {
+               b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPA0, pcomp->a0);
+               b43_phy_write(dev, B43_NPHY_C1_RXIQ_COMPB0, pcomp->b0);
+               b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPA1, pcomp->a1);
+               b43_phy_write(dev, B43_NPHY_C2_RXIQ_COMPB1, pcomp->b1);
        } else {
-               for (i = 0; i < 2; i++) {
-                       if ((code == 1 && i == 1) || (code == 2 && !i))
-                               continue;
-                       reg = (i == 0) ?
-                               B43_NPHY_AFECTL_OVER1 : B43_NPHY_AFECTL_OVER;
-                       b43_phy_maskset(dev, reg, 0xFDFF, 0x0200);
+               pcomp->a0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPA0);
+               pcomp->b0 = b43_phy_read(dev, B43_NPHY_C1_RXIQ_COMPB0);
+               pcomp->a1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPA1);
+               pcomp->b1 = b43_phy_read(dev, B43_NPHY_C2_RXIQ_COMPB1);
+       }
+ }
  
-                       if (type < 3) {
-                               reg = (i == 0) ?
-                                       B43_NPHY_AFECTL_C1 :
-                                       B43_NPHY_AFECTL_C2;
-                               b43_phy_maskset(dev, reg, 0xFCFF, 0);
+ #if 0
+ /* Ready but not used anywhere */
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhyCleanup */
+ static void b43_nphy_rx_cal_phy_cleanup(struct b43_wldev *dev, u8 core)
+ {
+       u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
  
-                               reg = (i == 0) ?
-                                       B43_NPHY_RFCTL_LUT_TRSW_UP1 :
-                                       B43_NPHY_RFCTL_LUT_TRSW_UP2;
-                               b43_phy_maskset(dev, reg, 0xFFC3, 0);
+       b43_phy_write(dev, B43_NPHY_RFSEQCA, regs[0]);
+       if (core == 0) {
+               b43_phy_write(dev, B43_NPHY_AFECTL_C1, regs[1]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, regs[2]);
+       } else {
+               b43_phy_write(dev, B43_NPHY_AFECTL_C2, regs[1]);
+               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, regs[2]);
+       }
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs[3]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs[4]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, regs[5]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, regs[6]);
+       b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S1, regs[7]);
+       b43_phy_write(dev, B43_NPHY_RFCTL_OVER, regs[8]);
+       b43_phy_write(dev, B43_NPHY_PAPD_EN0, regs[9]);
+       b43_phy_write(dev, B43_NPHY_PAPD_EN1, regs[10]);
+ }
  
-                               if (type == 0)
-                                       val = (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ) ? 4 : 8;
-                               else if (type == 1)
-                                       val = 16;
-                               else
-                                       val = 32;
-                               b43_phy_set(dev, reg, val);
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RxCalPhySetup */
+ static void b43_nphy_rx_cal_phy_setup(struct b43_wldev *dev, u8 core)
+ {
+       u8 rxval, txval;
+       u16 *regs = dev->phy.n->tx_rx_cal_phy_saveregs;
  
-                               reg = (i == 0) ?
-                                       B43_NPHY_TXF_40CO_B1S0 :
-                                       B43_NPHY_TXF_40CO_B32S1;
-                               b43_phy_set(dev, reg, 0x0020);
-                       } else {
-                               if (type == 6)
-                                       val = 0x0100;
-                               else if (type == 3)
-                                       val = 0x0200;
-                               else
-                                       val = 0x0300;
+       regs[0] = b43_phy_read(dev, B43_NPHY_RFSEQCA);
+       if (core == 0) {
+               regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
+               regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
+       } else {
+               regs[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
+               regs[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
+       }
+       regs[3] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
+       regs[4] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
+       regs[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1);
+       regs[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2);
+       regs[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S1);
+       regs[8] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER);
+       regs[9] = b43_phy_read(dev, B43_NPHY_PAPD_EN0);
+       regs[10] = b43_phy_read(dev, B43_NPHY_PAPD_EN1);
  
-                               reg = (i == 0) ?
-                                       B43_NPHY_AFECTL_C1 :
-                                       B43_NPHY_AFECTL_C2;
+       b43_phy_mask(dev, B43_NPHY_PAPD_EN0, ~0x0001);
+       b43_phy_mask(dev, B43_NPHY_PAPD_EN1, ~0x0001);
  
-                               b43_phy_maskset(dev, reg, 0xFCFF, val);
-                               b43_phy_maskset(dev, reg, 0xF3FF, val << 2);
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA,
+                       ~B43_NPHY_RFSEQCA_RXDIS & 0xFFFF,
+                       ((1 - core) << B43_NPHY_RFSEQCA_RXDIS_SHIFT));
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXEN,
+                       ((1 - core) << B43_NPHY_RFSEQCA_TXEN_SHIFT));
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_RXEN,
+                       (core << B43_NPHY_RFSEQCA_RXEN_SHIFT));
+       b43_phy_maskset(dev, B43_NPHY_RFSEQCA, ~B43_NPHY_RFSEQCA_TXDIS,
+                       (core << B43_NPHY_RFSEQCA_TXDIS_SHIFT));
  
-                               if (type != 3 && type != 6) {
-                                       enum ieee80211_band band =
-                                               b43_current_band(dev->wl);
+       if (core == 0) {
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C1, ~0x0007);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER1, 0x0007);
+       } else {
+               b43_phy_mask(dev, B43_NPHY_AFECTL_C2, ~0x0007);
+               b43_phy_set(dev, B43_NPHY_AFECTL_OVER, 0x0007);
+       }
  
-                                       if (b43_nphy_ipa(dev))
-                                               val = (band == IEEE80211_BAND_5GHZ) ? 0xC : 0xE;
-                                       else
-                                               val = 0x11;
-                                       reg = (i == 0) ? 0x2000 : 0x3000;
-                                       reg |= B2055_PADDRV;
-                                       b43_radio_write16(dev, reg, val);
+       b43_nphy_rf_control_intc_override(dev, 2, 0, 3);
+       b43_nphy_rf_control_override(dev, 8, 0, 3, false);
+       b43_nphy_force_rf_sequence(dev, B43_RFSEQ_RX2TX);
  
-                                       reg = (i == 0) ?
-                                               B43_NPHY_AFECTL_OVER1 :
-                                               B43_NPHY_AFECTL_OVER;
-                                       b43_phy_set(dev, reg, 0x0200);
-                               }
-                       }
-               }
+       if (core == 0) {
+               rxval = 1;
+               txval = 8;
+       } else {
+               rxval = 4;
+               txval = 2;
        }
+       b43_nphy_rf_control_intc_override(dev, 1, rxval, (core + 1));
+       b43_nphy_rf_control_intc_override(dev, 1, txval, (2 - core));
  }
+ #endif
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSISel */
- static void b43_nphy_rssi_select(struct b43_wldev *dev, u8 code, u8 type)
- {
-       if (dev->phy.rev >= 3)
-               b43_nphy_rev3_rssi_select(dev, code, type);
-       else
-               b43_nphy_rev2_rssi_select(dev, code, type);
- }
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SetRssi2055Vcm */
- static void b43_nphy_set_rssi_2055_vcm(struct b43_wldev *dev, u8 type, u8 *buf)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/CalcRxIqComp */
+ static void b43_nphy_calc_rx_iq_comp(struct b43_wldev *dev, u8 mask)
  {
        int i;
+       s32 iq;
+       u32 ii;
+       u32 qq;
+       int iq_nbits, qq_nbits;
+       int arsh, brsh;
+       u16 tmp, a, b;
+       struct nphy_iq_est est;
+       struct b43_phy_n_iq_comp old;
+       struct b43_phy_n_iq_comp new = { };
+       bool error = false;
+       if (mask == 0)
+               return;
+       b43_nphy_rx_iq_coeffs(dev, false, &old);
+       b43_nphy_rx_iq_coeffs(dev, true, &new);
+       b43_nphy_rx_iq_est(dev, &est, 0x4000, 32, false);
+       new = old;
        for (i = 0; i < 2; i++) {
-               if (type == 2) {
-                       if (i == 0) {
-                               b43_radio_maskset(dev, B2055_C1_B0NB_RSSIVCM,
-                                                 0xFC, buf[0]);
-                               b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
-                                                 0xFC, buf[1]);
-                       } else {
-                               b43_radio_maskset(dev, B2055_C2_B0NB_RSSIVCM,
-                                                 0xFC, buf[2 * i]);
-                               b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
-                                                 0xFC, buf[2 * i + 1]);
-                       }
+               if (i == 0 && (mask & 1)) {
+                       iq = est.iq0_prod;
+                       ii = est.i0_pwr;
+                       qq = est.q0_pwr;
+               } else if (i == 1 && (mask & 2)) {
+                       iq = est.iq1_prod;
+                       ii = est.i1_pwr;
+                       qq = est.q1_pwr;
                } else {
-                       if (i == 0)
-                               b43_radio_maskset(dev, B2055_C1_RX_BB_RSSICTL5,
-                                                 0xF3, buf[0] << 2);
-                       else
-                               b43_radio_maskset(dev, B2055_C2_RX_BB_RSSICTL5,
-                                                 0xF3, buf[2 * i + 1] << 2);
+                       continue;
                }
-       }
- }
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/PollRssi */
- static int b43_nphy_poll_rssi(struct b43_wldev *dev, u8 type, s32 *buf,
-                               u8 nsamp)
- {
-       int i;
-       int out;
-       u16 save_regs_phy[9];
-       u16 s[2];
-       if (dev->phy.rev >= 3) {
-               save_regs_phy[0] = b43_phy_read(dev,
-                                               B43_NPHY_RFCTL_LUT_TRSW_UP1);
-               save_regs_phy[1] = b43_phy_read(dev,
-                                               B43_NPHY_RFCTL_LUT_TRSW_UP2);
-               save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
-               save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
-               save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER1);
-               save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
-               save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B1S0);
-               save_regs_phy[7] = b43_phy_read(dev, B43_NPHY_TXF_40CO_B32S1);
-               save_regs_phy[8] = 0;
-       } else {
-               save_regs_phy[0] = b43_phy_read(dev, B43_NPHY_AFECTL_C1);
-               save_regs_phy[1] = b43_phy_read(dev, B43_NPHY_AFECTL_C2);
-               save_regs_phy[2] = b43_phy_read(dev, B43_NPHY_AFECTL_OVER);
-               save_regs_phy[3] = b43_phy_read(dev, B43_NPHY_RFCTL_CMD);
-               save_regs_phy[4] = b43_phy_read(dev, B43_NPHY_RFCTL_OVER);
-               save_regs_phy[5] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO1);
-               save_regs_phy[6] = b43_phy_read(dev, B43_NPHY_RFCTL_RSSIO2);
-               save_regs_phy[7] = 0;
-               save_regs_phy[8] = 0;
-       }
  
-       b43_nphy_rssi_select(dev, 5, type);
+               if (ii + qq < 2) {
+                       error = true;
+                       break;
+               }
  
-       if (dev->phy.rev < 2) {
-               save_regs_phy[8] = b43_phy_read(dev, B43_NPHY_GPIO_SEL);
-               b43_phy_write(dev, B43_NPHY_GPIO_SEL, 5);
-       }
+               iq_nbits = fls(abs(iq));
+               qq_nbits = fls(qq);
  
-       for (i = 0; i < 4; i++)
-               buf[i] = 0;
+               arsh = iq_nbits - 20;
+               if (arsh >= 0) {
+                       a = -((iq << (30 - iq_nbits)) + (ii >> (1 + arsh)));
+                       tmp = ii >> arsh;
+               } else {
+                       a = -((iq << (30 - iq_nbits)) + (ii << (-1 - arsh)));
+                       tmp = ii << -arsh;
+               }
+               if (tmp == 0) {
+                       error = true;
+                       break;
+               }
+               a /= tmp;
  
-       for (i = 0; i < nsamp; i++) {
-               if (dev->phy.rev < 2) {
-                       s[0] = b43_phy_read(dev, B43_NPHY_GPIO_LOOUT);
-                       s[1] = b43_phy_read(dev, B43_NPHY_GPIO_HIOUT);
+               brsh = qq_nbits - 11;
+               if (brsh >= 0) {
+                       b = (qq << (31 - qq_nbits));
+                       tmp = ii >> brsh;
                } else {
-                       s[0] = b43_phy_read(dev, B43_NPHY_RSSI1);
-                       s[1] = b43_phy_read(dev, B43_NPHY_RSSI2);
+                       b = (qq << (31 - qq_nbits));
+                       tmp = ii << -brsh;
+               }
+               if (tmp == 0) {
+                       error = true;
+                       break;
                }
+               b = int_sqrt(b / tmp - a * a) - (1 << 10);
  
-               buf[0] += ((s8)((s[0] & 0x3F) << 2)) >> 2;
-               buf[1] += ((s8)(((s[0] >> 8) & 0x3F) << 2)) >> 2;
-               buf[2] += ((s8)((s[1] & 0x3F) << 2)) >> 2;
-               buf[3] += ((s8)(((s[1] >> 8) & 0x3F) << 2)) >> 2;
+               if (i == 0 && (mask & 0x1)) {
+                       if (dev->phy.rev >= 3) {
+                               new.a0 = a & 0x3FF;
+                               new.b0 = b & 0x3FF;
+                       } else {
+                               new.a0 = b & 0x3FF;
+                               new.b0 = a & 0x3FF;
+                       }
+               } else if (i == 1 && (mask & 0x2)) {
+                       if (dev->phy.rev >= 3) {
+                               new.a1 = a & 0x3FF;
+                               new.b1 = b & 0x3FF;
+                       } else {
+                               new.a1 = b & 0x3FF;
+                               new.b1 = a & 0x3FF;
+                       }
+               }
        }
-       out = (buf[0] & 0xFF) << 24 | (buf[1] & 0xFF) << 16 |
-               (buf[2] & 0xFF) << 8 | (buf[3] & 0xFF);
  
-       if (dev->phy.rev < 2)
-               b43_phy_write(dev, B43_NPHY_GPIO_SEL, save_regs_phy[8]);
+       if (error)
+               new = old;
  
-       if (dev->phy.rev >= 3) {
-               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1,
-                               save_regs_phy[0]);
-               b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2,
-                               save_regs_phy[1]);
-               b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[2]);
-               b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[3]);
-               b43_phy_write(dev, B43_NPHY_AFECTL_OVER1, save_regs_phy[4]);
-               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[5]);
-               b43_phy_write(dev, B43_NPHY_TXF_40CO_B1S0, save_regs_phy[6]);
-               b43_phy_write(dev, B43_NPHY_TXF_40CO_B32S1, save_regs_phy[7]);
-       } else {
-               b43_phy_write(dev, B43_NPHY_AFECTL_C1, save_regs_phy[0]);
-               b43_phy_write(dev, B43_NPHY_AFECTL_C2, save_regs_phy[1]);
-               b43_phy_write(dev, B43_NPHY_AFECTL_OVER, save_regs_phy[2]);
-               b43_phy_write(dev, B43_NPHY_RFCTL_CMD, save_regs_phy[3]);
-               b43_phy_write(dev, B43_NPHY_RFCTL_OVER, save_regs_phy[4]);
-               b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO1, save_regs_phy[5]);
-               b43_phy_write(dev, B43_NPHY_RFCTL_RSSIO2, save_regs_phy[6]);
-       }
+       b43_nphy_rx_iq_coeffs(dev, true, &new);
+ }
  
-       return out;
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxIqWar */
+ static void b43_nphy_tx_iq_workaround(struct b43_wldev *dev)
+ {
+       u16 array[4];
+       b43_ntab_read_bulk(dev, B43_NTAB16(0xF, 0x50), 4, array);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW0, array[0]);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW1, array[1]);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW2, array[2]);
+       b43_shm_write16(dev, B43_SHM_SHARED, B43_SHM_SH_NPHY_TXIQW3, array[3]);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal */
- static void b43_nphy_rev2_rssi_cal(struct b43_wldev *dev, u8 type)
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/stop-playback */
+ static void b43_nphy_stop_playback(struct b43_wldev *dev)
  {
-       int i, j;
-       u8 state[4];
-       u8 code, val;
-       u16 class, override;
-       u8 regs_save_radio[2];
-       u16 regs_save_phy[2];
+       struct b43_phy_n *nphy = dev->phy.n;
+       u16 tmp;
  
-       s8 offset[4];
-       u8 core;
-       u8 rail;
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
  
-       u16 clip_state[2];
-       u16 clip_off[2] = { 0xFFFF, 0xFFFF };
-       s32 results_min[4] = { };
-       u8 vcm_final[4] = { };
-       s32 results[4][4] = { };
-       s32 miniq[4][2] = { };
+       tmp = b43_phy_read(dev, B43_NPHY_SAMP_STAT);
+       if (tmp & 0x1)
+               b43_phy_set(dev, B43_NPHY_SAMP_CMD, B43_NPHY_SAMP_CMD_STOP);
+       else if (tmp & 0x2)
+               b43_phy_mask(dev, B43_NPHY_IQLOCAL_CMDGCTL, 0x7FFF);
  
-       if (type == 2) {
-               code = 0;
-               val = 6;
-       } else if (type < 2) {
-               code = 25;
-               val = 4;
-       } else {
-               B43_WARN_ON(1);
-               return;
-       }
+       b43_phy_mask(dev, B43_NPHY_SAMP_CMD, ~0x0004);
  
-       class = b43_nphy_classifier(dev, 0, 0);
-       b43_nphy_classifier(dev, 7, 4);
-       b43_nphy_read_clip_detection(dev, clip_state);
-       b43_nphy_write_clip_detection(dev, clip_off);
+       if (nphy->bb_mult_save & 0x80000000) {
+               tmp = nphy->bb_mult_save & 0xFFFF;
+               b43_ntab_write(dev, B43_NTAB16(15, 87), tmp);
+               nphy->bb_mult_save = 0;
+       }
  
-       if (b43_current_band(dev->wl) == IEEE80211_BAND_5GHZ)
-               override = 0x140;
-       else
-               override = 0x110;
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+ }
  
-       regs_save_phy[0] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC1);
-       regs_save_radio[0] = b43_radio_read16(dev, B2055_C1_PD_RXTX);
-       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, override);
-       b43_radio_write16(dev, B2055_C1_PD_RXTX, val);
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SpurWar */
+ static void b43_nphy_spur_workaround(struct b43_wldev *dev)
+ {
+       struct b43_phy_n *nphy = dev->phy.n;
  
-       regs_save_phy[1] = b43_phy_read(dev, B43_NPHY_RFCTL_INTC2);
-       regs_save_radio[1] = b43_radio_read16(dev, B2055_C2_PD_RXTX);
-       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, override);
-       b43_radio_write16(dev, B2055_C2_PD_RXTX, val);
+       u8 channel = dev->phy.channel;
+       int tone[2] = { 57, 58 };
+       u32 noise[2] = { 0x3FF, 0x3FF };
  
-       state[0] = b43_radio_read16(dev, B2055_C1_PD_RSSIMISC) & 0x07;
-       state[1] = b43_radio_read16(dev, B2055_C2_PD_RSSIMISC) & 0x07;
-       b43_radio_mask(dev, B2055_C1_PD_RSSIMISC, 0xF8);
-       b43_radio_mask(dev, B2055_C2_PD_RSSIMISC, 0xF8);
-       state[2] = b43_radio_read16(dev, B2055_C1_SP_RSSI) & 0x07;
-       state[3] = b43_radio_read16(dev, B2055_C2_SP_RSSI) & 0x07;
+       B43_WARN_ON(dev->phy.rev < 3);
  
-       b43_nphy_rssi_select(dev, 5, type);
-       b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 0, type);
-       b43_nphy_scale_offset_rssi(dev, 0, 0, 5, 1, type);
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 1);
  
-       for (i = 0; i < 4; i++) {
-               u8 tmp[4];
-               for (j = 0; j < 4; j++)
-                       tmp[j] = i;
-               if (type != 1)
-                       b43_nphy_set_rssi_2055_vcm(dev, type, tmp);
-               b43_nphy_poll_rssi(dev, type, results[i], 8);
-               if (type < 2)
-                       for (j = 0; j < 2; j++)
-                               miniq[i][j] = min(results[i][2 * j],
-                                               results[i][2 * j + 1]);
+       if (nphy->gband_spurwar_en) {
+               /* TODO: N PHY Adjust Analog Pfbw (7) */
+               if (channel == 11 && dev->phy.is_40mhz)
+                       ; /* TODO: N PHY Adjust Min Noise Var(2, tone, noise)*/
+               else
+                       ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
+               /* TODO: N PHY Adjust CRS Min Power (0x1E) */
        }
  
-       for (i = 0; i < 4; i++) {
-               s32 mind = 40;
-               u8 minvcm = 0;
-               s32 minpoll = 249;
-               s32 curr;
-               for (j = 0; j < 4; j++) {
-                       if (type == 2)
-                               curr = abs(results[j][i]);
-                       else
-                               curr = abs(miniq[j][i / 2] - code * 8);
-                       if (curr < mind) {
-                               mind = curr;
-                               minvcm = j;
+       if (nphy->aband_spurwar_en) {
+               if (channel == 54) {
+                       tone[0] = 0x20;
+                       noise[0] = 0x25F;
+               } else if (channel == 38 || channel == 102 || channel == 118) {
+                       if (0 /* FIXME */) {
+                               tone[0] = 0x20;
+                               noise[0] = 0x21F;
+                       } else {
+                               tone[0] = 0;
+                               noise[0] = 0;
                        }
-                       if (results[j][i] < minpoll)
-                               minpoll = results[j][i];
+               } else if (channel == 134) {
+                       tone[0] = 0x20;
+                       noise[0] = 0x21F;
+               } else if (channel == 151) {
+                       tone[0] = 0x10;
+                       noise[0] = 0x23F;
+               } else if (channel == 153 || channel == 161) {
+                       tone[0] = 0x30;
+                       noise[0] = 0x23F;
+               } else {
+                       tone[0] = 0;
+                       noise[0] = 0;
                }
-               results_min[i] = minpoll;
-               vcm_final[i] = minvcm;
-       }
-       if (type != 1)
-               b43_nphy_set_rssi_2055_vcm(dev, type, vcm_final);
  
-       for (i = 0; i < 4; i++) {
-               offset[i] = (code * 8) - results[vcm_final[i]][i];
-               if (offset[i] < 0)
-                       offset[i] = -((abs(offset[i]) + 4) / 8);
+               if (!tone[0] && !noise[0])
+                       ; /* TODO: N PHY Adjust Min Noise Var(1, tone, noise)*/
                else
-                       offset[i] = (offset[i] + 4) / 8;
+                       ; /* TODO: N PHY Adjust Min Noise Var(0, NULL, NULL)*/
+       }
  
-               if (results_min[i] == 248)
-                       offset[i] = code - 32;
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, 0);
+ }
  
-               core = (i / 2) ? 2 : 1;
-               rail = (i % 2) ? 1 : 0;
+ /*
+  * Transmits a known value for LO calibration
+  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/TXTone
+  */
+ static int b43_nphy_tx_tone(struct b43_wldev *dev, u32 freq, u16 max_val,
+                               bool iqmode, bool dac_test)
+ {
+       u16 samp = b43_nphy_gen_load_samples(dev, freq, max_val, dac_test);
+       if (samp == 0)
+               return -1;
+       b43_nphy_run_samples(dev, samp, 0xFFFF, 0, iqmode, dac_test);
+       return 0;
+ }
  
-               b43_nphy_scale_offset_rssi(dev, 0, offset[i], core, rail,
-                                               type);
-       }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxPwrCtrlCoefSetup */
+ static void b43_nphy_tx_pwr_ctrl_coef_setup(struct b43_wldev *dev)
+ {
+       struct b43_phy_n *nphy = dev->phy.n;
+       int i, j;
+       u32 tmp;
+       u32 cur_real, cur_imag, real_part, imag_part;
  
-       b43_radio_maskset(dev, B2055_C1_PD_RSSIMISC, 0xF8, state[0]);
-       b43_radio_maskset(dev, B2055_C2_PD_RSSIMISC, 0xF8, state[1]);
+       u16 buffer[7];
  
-       switch (state[2]) {
-       case 1:
-               b43_nphy_rssi_select(dev, 1, 2);
-               break;
-       case 4:
-               b43_nphy_rssi_select(dev, 1, 0);
-               break;
-       case 2:
-               b43_nphy_rssi_select(dev, 1, 1);
-               break;
-       default:
-               b43_nphy_rssi_select(dev, 1, 1);
-               break;
-       }
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, true);
  
-       switch (state[3]) {
-       case 1:
-               b43_nphy_rssi_select(dev, 2, 2);
-               break;
-       case 4:
-               b43_nphy_rssi_select(dev, 2, 0);
-               break;
-       default:
-               b43_nphy_rssi_select(dev, 2, 1);
-               break;
-       }
+       b43_ntab_read_bulk(dev, B43_NTAB16(15, 80), 7, buffer);
  
-       b43_nphy_rssi_select(dev, 0, type);
+       for (i = 0; i < 2; i++) {
+               tmp = ((buffer[i * 2] & 0x3FF) << 10) |
+                       (buffer[i * 2 + 1] & 0x3FF);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+                               (((i + 26) << 10) | 320));
+               for (j = 0; j < 128; j++) {
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
+                                       ((tmp >> 16) & 0xFFFF));
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (tmp & 0xFFFF));
+               }
+       }
  
-       b43_phy_write(dev, B43_NPHY_RFCTL_INTC1, regs_save_phy[0]);
-       b43_radio_write16(dev, B2055_C1_PD_RXTX, regs_save_radio[0]);
-       b43_phy_write(dev, B43_NPHY_RFCTL_INTC2, regs_save_phy[1]);
-       b43_radio_write16(dev, B2055_C2_PD_RXTX, regs_save_radio[1]);
+       for (i = 0; i < 2; i++) {
+               tmp = buffer[5 + i];
+               real_part = (tmp >> 8) & 0xFF;
+               imag_part = (tmp & 0xFF);
+               b43_phy_write(dev, B43_NPHY_TABLE_ADDR,
+                               (((i + 26) << 10) | 448));
  
-       b43_nphy_classifier(dev, 7, class);
-       b43_nphy_write_clip_detection(dev, clip_state);
-       /* Specs don't say about reset here, but it makes wl and b43 dumps
-          identical, it really seems wl performs this */
-       b43_nphy_reset_cca(dev);
- }
+               if (dev->phy.rev >= 3) {
+                       cur_real = real_part;
+                       cur_imag = imag_part;
+                       tmp = ((cur_real & 0xFF) << 8) | (cur_imag & 0xFF);
+               }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICalRev3 */
- static void b43_nphy_rev3_rssi_cal(struct b43_wldev *dev)
- {
-       /* TODO */
- }
+               for (j = 0; j < 128; j++) {
+                       if (dev->phy.rev < 3) {
+                               cur_real = (real_part * loscale[j] + 128) >> 8;
+                               cur_imag = (imag_part * loscale[j] + 128) >> 8;
+                               tmp = ((cur_real & 0xFF) << 8) |
+                                       (cur_imag & 0xFF);
+                       }
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATAHI,
+                                       ((tmp >> 16) & 0xFFFF));
+                       b43_phy_write(dev, B43_NPHY_TABLE_DATALO,
+                                       (tmp & 0xFFFF));
+               }
+       }
  
- /*
-  * RSSI Calibration
-  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/RSSICal
-  */
- static void b43_nphy_rssi_cal(struct b43_wldev *dev)
- {
        if (dev->phy.rev >= 3) {
-               b43_nphy_rev3_rssi_cal(dev);
-       } else {
-               b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Z);
-               b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_X);
-               b43_nphy_rev2_rssi_cal(dev, B43_NPHY_RSSI_Y);
+               b43_shm_write16(dev, B43_SHM_SHARED,
+                               B43_SHM_SH_NPHY_TXPWR_INDX0, 0xFFFF);
+               b43_shm_write16(dev, B43_SHM_SHARED,
+                               B43_SHM_SH_NPHY_TXPWR_INDX1, 0xFFFF);
        }
+       if (nphy->hang_avoid)
+               b43_nphy_stay_in_carrier_search(dev, false);
  }
  
  /*
@@@ -2846,24 -2778,6 +2778,6 @@@ static void b43_nphy_restore_rssi_cal(s
        b43_phy_write(dev, B43_NPHY_RSSIMC_1Q_RSSI_Y, rssical_phy_regs[11]);
  }
  
- /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/GetIpaGainTbl */
- static const u32 *b43_nphy_get_ipa_gain_table(struct b43_wldev *dev)
- {
-       if (b43_current_band(dev->wl) == IEEE80211_BAND_2GHZ) {
-               if (dev->phy.rev >= 6) {
-                       if (dev->dev->chip_id == 47162)
-                               return txpwrctrl_tx_gain_ipa_rev5;
-                       return txpwrctrl_tx_gain_ipa_rev6;
-               } else if (dev->phy.rev >= 5) {
-                       return txpwrctrl_tx_gain_ipa_rev5;
-               } else {
-                       return txpwrctrl_tx_gain_ipa;
-               }
-       } else {
-               return txpwrctrl_tx_gain_ipa_5g;
-       }
- }
  /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/TxCalRadioSetup */
  static void b43_nphy_tx_cal_radio_setup(struct b43_wldev *dev)
  {
@@@ -3375,7 -3289,7 +3289,7 @@@ static int b43_nphy_cal_tx_iq_lo(struc
  
        if (dev->phy.rev >= 4) {
                avoid = nphy->hang_avoid;
 -              nphy->hang_avoid = 0;
 +              nphy->hang_avoid = false;
        }
  
        b43_ntab_read_bulk(dev, B43_NTAB16(7, 0x110), 2, save);
  
                        if (phy6or5x && updated[core] == 0) {
                                b43_nphy_update_tx_cal_ladder(dev, core);
 -                              updated[core] = 1;
 +                              updated[core] = true;
                        }
  
                        tmp = (params[core].ncorr[type] << 8) | 0x66;
@@@ -3847,10 -3761,104 +3761,104 @@@ static void b43_nphy_set_rx_core_state(
        b43_mac_enable(dev);
  }
  
+ /**************************************************
+  * N-PHY init
+  **************************************************/
  /*
-  * Init N-PHY
-  * http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N
+  * Upload the N-PHY tables.
+  * http://bcm-v4.sipsolutions.net/802.11/PHY/N/InitTables
   */
+ static void b43_nphy_tables_init(struct b43_wldev *dev)
+ {
+       if (dev->phy.rev < 3)
+               b43_nphy_rev0_1_2_tables_init(dev);
+       else
+               b43_nphy_rev3plus_tables_init(dev);
+ }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/MIMOConfig */
+ static void b43_nphy_update_mimo_config(struct b43_wldev *dev, s32 preamble)
+ {
+       u16 mimocfg = b43_phy_read(dev, B43_NPHY_MIMOCFG);
+       mimocfg |= B43_NPHY_MIMOCFG_AUTO;
+       if (preamble == 1)
+               mimocfg |= B43_NPHY_MIMOCFG_GFMIX;
+       else
+               mimocfg &= ~B43_NPHY_MIMOCFG_GFMIX;
+       b43_phy_write(dev, B43_NPHY_MIMOCFG, mimocfg);
+ }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/BPHYInit */
+ static void b43_nphy_bphy_init(struct b43_wldev *dev)
+ {
+       unsigned int i;
+       u16 val;
+       val = 0x1E1F;
+       for (i = 0; i < 16; i++) {
+               b43_phy_write(dev, B43_PHY_N_BMODE(0x88 + i), val);
+               val -= 0x202;
+       }
+       val = 0x3E3F;
+       for (i = 0; i < 16; i++) {
+               b43_phy_write(dev, B43_PHY_N_BMODE(0x98 + i), val);
+               val -= 0x202;
+       }
+       b43_phy_write(dev, B43_PHY_N_BMODE(0x38), 0x668);
+ }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/N/SuperSwitchInit */
+ static void b43_nphy_superswitch_init(struct b43_wldev *dev, bool init)
+ {
+       if (dev->phy.rev >= 3) {
+               if (!init)
+                       return;
+               if (0 /* FIXME */) {
+                       b43_ntab_write(dev, B43_NTAB16(9, 2), 0x211);
+                       b43_ntab_write(dev, B43_NTAB16(9, 3), 0x222);
+                       b43_ntab_write(dev, B43_NTAB16(9, 8), 0x144);
+                       b43_ntab_write(dev, B43_NTAB16(9, 12), 0x188);
+               }
+       } else {
+               b43_phy_write(dev, B43_NPHY_GPIO_LOOEN, 0);
+               b43_phy_write(dev, B43_NPHY_GPIO_HIOEN, 0);
+               switch (dev->dev->bus_type) {
+ #ifdef CONFIG_B43_BCMA
+               case B43_BUS_BCMA:
+                       bcma_chipco_gpio_control(&dev->dev->bdev->bus->drv_cc,
+                                                0xFC00, 0xFC00);
+                       break;
+ #endif
+ #ifdef CONFIG_B43_SSB
+               case B43_BUS_SSB:
+                       ssb_chipco_gpio_control(&dev->dev->sdev->bus->chipco,
+                                               0xFC00, 0xFC00);
+                       break;
+ #endif
+               }
+               b43_write32(dev, B43_MMIO_MACCTL,
+                       b43_read32(dev, B43_MMIO_MACCTL) &
+                       ~B43_MACCTL_GPOUTSMSK);
+               b43_write16(dev, B43_MMIO_GPIO_MASK,
+                       b43_read16(dev, B43_MMIO_GPIO_MASK) | 0xFC00);
+               b43_write16(dev, B43_MMIO_GPIO_CONTROL,
+                       b43_read16(dev, B43_MMIO_GPIO_CONTROL) & ~0xFC00);
+               if (init) {
+                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO1, 0x2D8);
+                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP1, 0x301);
+                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_LO2, 0x2D8);
+                       b43_phy_write(dev, B43_NPHY_RFCTL_LUT_TRSW_UP2, 0x301);
+               }
+       }
+ }
+ /* http://bcm-v4.sipsolutions.net/802.11/PHY/Init/N */
  int b43_phy_initn(struct b43_wldev *dev)
  {
        struct ssb_sprom *sprom = dev->dev->bus_sprom;
        return 0;
  }
  
+ /**************************************************
+  * Channel switching ops.
+  **************************************************/
+ static void b43_chantab_phy_upload(struct b43_wldev *dev,
+                                  const struct b43_phy_n_sfo_cfg *e)
+ {
+       b43_phy_write(dev, B43_NPHY_BW1A, e->phy_bw1a);
+       b43_phy_write(dev, B43_NPHY_BW2, e->phy_bw2);
+       b43_phy_write(dev, B43_NPHY_BW3, e->phy_bw3);
+       b43_phy_write(dev, B43_NPHY_BW4, e->phy_bw4);
+       b43_phy_write(dev, B43_NPHY_BW5, e->phy_bw5);
+       b43_phy_write(dev, B43_NPHY_BW6, e->phy_bw6);
+ }
  /* http://bcm-v4.sipsolutions.net/802.11/PmuSpurAvoid */
  static void b43_nphy_pmu_spur_avoid(struct b43_wldev *dev, bool avoid)
  {
-       struct bcma_drv_cc *cc;
-       u32 pmu_ctl;
+       struct bcma_drv_cc __maybe_unused *cc;
+       u32 __maybe_unused pmu_ctl;
  
        switch (dev->dev->bus_type) {
  #ifdef CONFIG_B43_BCMA
@@@ -4260,6 -4283,10 +4283,10 @@@ static int b43_nphy_set_channel(struct 
        return 0;
  }
  
+ /**************************************************
+  * Basic PHY ops.
+  **************************************************/
  static int b43_nphy_op_allocate(struct b43_wldev *dev)
  {
        struct b43_phy_n *nphy;
index 2c3a99d6c9a6d40981e2fb369ad54f2f336dd411,72bee2c049574d2a914baa9ffd6ea0c365ea6949..eb9eb766ac270d5e3011b98568343eeba12c5833
@@@ -52,7 -52,7 +52,7 @@@ MODULE_LICENSE("Dual BSD/GPL")
  
  /* Interface control information */
  struct brcmf_if {
-       struct brcmf_info *info;        /* back pointer to brcmf_info */
+       struct brcmf_pub *drvr; /* back pointer to brcmf_pub */
        /* OS/stack specifics */
        struct net_device *ndev;
        struct net_device_stats stats;
        u8 mac_addr[ETH_ALEN];  /* assigned MAC address */
  };
  
- /* Local private structure (extension of pub) */
- struct brcmf_info {
-       struct brcmf_pub pub;
-       /* OS/stack specifics */
-       struct brcmf_if *iflist[BRCMF_MAX_IFS];
-       struct mutex proto_block;
-       struct work_struct setmacaddr_work;
-       struct work_struct multicast_work;
-       u8 macvalue[ETH_ALEN];
-       atomic_t pend_8021x_cnt;
- };
  /* Error bits */
  int brcmf_msg_level = BRCMF_ERROR_VAL;
  module_param(brcmf_msg_level, int, 0);
  
- int brcmf_ifname2idx(struct brcmf_info *drvr_priv, char *name)
+ int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name)
  {
        int i = BRCMF_MAX_IFS;
        struct brcmf_if *ifp;
@@@ -88,7 -73,7 +73,7 @@@
                return 0;
  
        while (--i > 0) {
-               ifp = drvr_priv->iflist[i];
+               ifp = drvr->iflist[i];
                if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ))
                        break;
        }
  
  char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
  {
-       struct brcmf_info *drvr_priv = drvr->info;
        if (ifidx < 0 || ifidx >= BRCMF_MAX_IFS) {
                brcmf_dbg(ERROR, "ifidx %d out of range\n", ifidx);
                return "<if_bad>";
        }
  
-       if (drvr_priv->iflist[ifidx] == NULL) {
+       if (drvr->iflist[ifidx] == NULL) {
                brcmf_dbg(ERROR, "null i/f %d\n", ifidx);
                return "<if_null>";
        }
  
-       if (drvr_priv->iflist[ifidx]->ndev)
-               return drvr_priv->iflist[ifidx]->ndev->name;
+       if (drvr->iflist[ifidx]->ndev)
+               return drvr->iflist[ifidx]->ndev->name;
  
        return "<if_none>";
  }
@@@ -131,10 -114,10 +114,10 @@@ static void _brcmf_set_multicast_list(s
        uint buflen;
        int ret;
  
-       struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
+       struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
                                                    multicast_work);
  
-       ndev = drvr_priv->iflist[0]->ndev;
+       ndev = drvr->iflist[0]->ndev;
        cnt = netdev_mc_count(ndev);
  
        /* Determine initial value of allmulti flag */
        dcmd.len = buflen;
        dcmd.set = true;
  
-       ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
+       ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
        if (ret < 0) {
                brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n",
-                         brcmf_ifname(&drvr_priv->pub, 0), cnt);
+                         brcmf_ifname(drvr, 0), cnt);
                dcmd_value = cnt ? true : dcmd_value;
        }
  
            ("allmulti", (void *)&dcmd_le_value,
            sizeof(dcmd_le_value), buf, buflen)) {
                brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
-                         brcmf_ifname(&drvr_priv->pub, 0),
+                         brcmf_ifname(drvr, 0),
                          (int)sizeof(dcmd_value), buflen);
                kfree(buf);
                return;
        dcmd.len = buflen;
        dcmd.set = true;
  
-       ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
+       ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
        if (ret < 0) {
                brcmf_dbg(ERROR, "%s: set allmulti %d failed\n",
-                         brcmf_ifname(&drvr_priv->pub, 0),
+                         brcmf_ifname(drvr, 0),
                          le32_to_cpu(dcmd_le_value));
        }
  
        dcmd.len = sizeof(dcmd_le_value);
        dcmd.set = true;
  
-       ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
+       ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
        if (ret < 0) {
                brcmf_dbg(ERROR, "%s: set promisc %d failed\n",
-                         brcmf_ifname(&drvr_priv->pub, 0),
+                         brcmf_ifname(drvr, 0),
                          le32_to_cpu(dcmd_le_value));
        }
  }
@@@ -241,14 -224,14 +224,14 @@@ _brcmf_set_mac_address(struct work_stru
        struct brcmf_dcmd dcmd;
        int ret;
  
-       struct brcmf_info *drvr_priv = container_of(work, struct brcmf_info,
+       struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
                                                    setmacaddr_work);
  
        brcmf_dbg(TRACE, "enter\n");
-       if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr_priv->macvalue,
+       if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr->macvalue,
                           ETH_ALEN, buf, 32)) {
                brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n",
-                         brcmf_ifname(&drvr_priv->pub, 0));
+                         brcmf_ifname(drvr, 0));
                return;
        }
        memset(&dcmd, 0, sizeof(dcmd));
        dcmd.len = 32;
        dcmd.set = true;
  
-       ret = brcmf_proto_dcmd(&drvr_priv->pub, 0, &dcmd, dcmd.len);
+       ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
        if (ret < 0)
                brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n",
-                         brcmf_ifname(&drvr_priv->pub, 0));
+                         brcmf_ifname(drvr, 0));
        else
-               memcpy(drvr_priv->iflist[0]->ndev->dev_addr,
-                      drvr_priv->macvalue, ETH_ALEN);
+               memcpy(drvr->iflist[0]->ndev->dev_addr,
+                      drvr->macvalue, ETH_ALEN);
  
        return;
  }
  static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
  {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_info *drvr_priv = ifp->info;
+       struct brcmf_pub *drvr = ifp->drvr;
        struct sockaddr *sa = (struct sockaddr *)addr;
  
-       memcpy(&drvr_priv->macvalue, sa->sa_data, ETH_ALEN);
-       schedule_work(&drvr_priv->setmacaddr_work);
+       memcpy(&drvr->macvalue, sa->sa_data, ETH_ALEN);
+       schedule_work(&drvr->setmacaddr_work);
        return 0;
  }
  
  static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
  {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_info *drvr_priv = ifp->info;
+       struct brcmf_pub *drvr = ifp->drvr;
  
-       schedule_work(&drvr_priv->multicast_work);
+       schedule_work(&drvr->multicast_work);
  }
  
  int brcmf_sendpkt(struct brcmf_pub *drvr, int ifidx, struct sk_buff *pktbuf)
  {
-       struct brcmf_info *drvr_priv = drvr->info;
        /* Reject if down */
-       if (!drvr->up || (drvr->bus_if->state == BRCMF_BUS_DOWN))
+       if (!drvr->bus_if->drvr_up || (drvr->bus_if->state == BRCMF_BUS_DOWN))
                return -ENODEV;
  
        /* Update multicast statistic */
                if (is_multicast_ether_addr(eh->h_dest))
                        drvr->tx_multicast++;
                if (ntohs(eh->h_proto) == ETH_P_PAE)
-                       atomic_inc(&drvr_priv->pend_8021x_cnt);
+                       atomic_inc(&drvr->pend_8021x_cnt);
        }
  
        /* If the protocol uses a data header, apply it */
        brcmf_proto_hdrpush(drvr, ifidx, pktbuf);
  
        /* Use bus module to send data frame */
-       return brcmf_sdbrcm_bus_txdata(drvr->dev, pktbuf);
+       return drvr->bus_if->brcmf_bus_txdata(drvr->dev, pktbuf);
  }
  
  static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
  {
        int ret;
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_info *drvr_priv = ifp->info;
+       struct brcmf_pub *drvr = ifp->drvr;
  
        brcmf_dbg(TRACE, "Enter\n");
  
        /* Reject if down */
-       if (!drvr_priv->pub.up ||
-           (drvr_priv->pub.bus_if->state == BRCMF_BUS_DOWN)) {
-               brcmf_dbg(ERROR, "xmit rejected pub.up=%d state=%d\n",
-                         drvr_priv->pub.up,
-                         drvr_priv->pub.bus_if->state);
+       if (!drvr->bus_if->drvr_up ||
+           (drvr->bus_if->state == BRCMF_BUS_DOWN)) {
+               brcmf_dbg(ERROR, "xmit rejected drvup=%d state=%d\n",
+                         drvr->bus_if->drvr_up,
+                         drvr->bus_if->state);
                netif_stop_queue(ndev);
                return -ENODEV;
        }
  
-       if (!drvr_priv->iflist[ifp->idx]) {
+       if (!drvr->iflist[ifp->idx]) {
                brcmf_dbg(ERROR, "bad ifidx %d\n", ifp->idx);
                netif_stop_queue(ndev);
                return -ENODEV;
        }
  
        /* Make sure there's enough room for any header */
-       if (skb_headroom(skb) < drvr_priv->pub.hdrlen) {
+       if (skb_headroom(skb) < drvr->hdrlen) {
                struct sk_buff *skb2;
  
                brcmf_dbg(INFO, "%s: insufficient headroom\n",
-                         brcmf_ifname(&drvr_priv->pub, ifp->idx));
-               drvr_priv->pub.tx_realloc++;
-               skb2 = skb_realloc_headroom(skb, drvr_priv->pub.hdrlen);
+                         brcmf_ifname(drvr, ifp->idx));
+               drvr->bus_if->tx_realloc++;
+               skb2 = skb_realloc_headroom(skb, drvr->hdrlen);
                dev_kfree_skb(skb);
                skb = skb2;
                if (skb == NULL) {
                        brcmf_dbg(ERROR, "%s: skb_realloc_headroom failed\n",
-                                 brcmf_ifname(&drvr_priv->pub, ifp->idx));
+                                 brcmf_ifname(drvr, ifp->idx));
                        ret = -ENOMEM;
                        goto done;
                }
        }
  
-       ret = brcmf_sendpkt(&drvr_priv->pub, ifp->idx, skb);
+       ret = brcmf_sendpkt(drvr, ifp->idx, skb);
  
  done:
        if (ret)
-               drvr_priv->pub.dstats.tx_dropped++;
+               drvr->bus_if->dstats.tx_dropped++;
        else
-               drvr_priv->pub.tx_packets++;
+               drvr->bus_if->dstats.tx_packets++;
  
        /* Return ok: we always eat the packet */
        return 0;
  }
  
- void brcmf_txflowcontrol(struct brcmf_pub *drvr, int ifidx, bool state)
+ void brcmf_txflowcontrol(struct device *dev, int ifidx, bool state)
  {
        struct net_device *ndev;
-       struct brcmf_info *drvr_priv = drvr->info;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
  
        brcmf_dbg(TRACE, "Enter\n");
  
-       drvr->txoff = state;
-       ndev = drvr_priv->iflist[ifidx]->ndev;
+       ndev = drvr->iflist[ifidx]->ndev;
        if (state == ON)
                netif_stop_queue(ndev);
        else
                netif_wake_queue(ndev);
  }
  
- static int brcmf_host_event(struct brcmf_info *drvr_priv, int *ifidx,
+ static int brcmf_host_event(struct brcmf_pub *drvr, int *ifidx,
                            void *pktdata, struct brcmf_event_msg *event,
                            void **data)
  {
        int bcmerror = 0;
  
-       bcmerror = brcmf_c_host_event(drvr_priv, ifidx, pktdata, event, data);
+       bcmerror = brcmf_c_host_event(drvr, ifidx, pktdata, event, data);
        if (bcmerror != 0)
                return bcmerror;
  
-       if (drvr_priv->iflist[*ifidx]->ndev)
-               brcmf_cfg80211_event(drvr_priv->iflist[*ifidx]->ndev,
+       if (drvr->iflist[*ifidx]->ndev)
+               brcmf_cfg80211_event(drvr->iflist[*ifidx]->ndev,
                                     event, *data);
  
        return bcmerror;
  }
  
- void brcmf_rx_frame(struct brcmf_pub *drvr, int ifidx,
+ void brcmf_rx_frame(struct device *dev, int ifidx,
                    struct sk_buff_head *skb_list)
  {
-       struct brcmf_info *drvr_priv = drvr->info;
        unsigned char *eth;
        uint len;
        void *data;
        struct sk_buff *skb, *pnext;
        struct brcmf_if *ifp;
        struct brcmf_event_msg event;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
  
        brcmf_dbg(TRACE, "Enter\n");
  
                eth = skb->data;
                len = skb->len;
  
-               ifp = drvr_priv->iflist[ifidx];
+               ifp = drvr->iflist[ifidx];
                if (ifp == NULL)
-                       ifp = drvr_priv->iflist[0];
+                       ifp = drvr->iflist[0];
  
                if (!ifp || !ifp->ndev ||
                    ifp->ndev->reg_state != NETREG_REGISTERED) {
                skb->protocol = eth_type_trans(skb, skb->dev);
  
                if (skb->pkt_type == PACKET_MULTICAST)
-                       drvr_priv->pub.rx_multicast++;
+                       bus_if->dstats.multicast++;
  
                skb->data = eth;
                skb->len = len;
  
                /* Process special event packets and then discard them */
                if (ntohs(skb->protocol) == ETH_P_LINK_CTL)
-                       brcmf_host_event(drvr_priv, &ifidx,
+                       brcmf_host_event(drvr, &ifidx,
                                          skb_mac_header(skb),
                                          &event, &data);
  
-               if (drvr_priv->iflist[ifidx]) {
-                       ifp = drvr_priv->iflist[ifidx];
+               if (drvr->iflist[ifidx]) {
+                       ifp = drvr->iflist[ifidx];
                        ifp->ndev->last_rx = jiffies;
                }
  
-               drvr->dstats.rx_bytes += skb->len;
-               drvr->rx_packets++;     /* Local count */
+               bus_if->dstats.rx_bytes += skb->len;
+               bus_if->dstats.rx_packets++;    /* Local count */
  
                if (in_interrupt())
                        netif_rx(skb);
        }
  }
  
- void brcmf_txcomplete(struct brcmf_pub *drvr, struct sk_buff *txp, bool success)
+ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
  {
        uint ifidx;
-       struct brcmf_info *drvr_priv = drvr->info;
        struct ethhdr *eh;
        u16 type;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
  
-       brcmf_proto_hdrpull(drvr, &ifidx, txp);
+       brcmf_proto_hdrpull(dev, &ifidx, txp);
  
        eh = (struct ethhdr *)(txp->data);
        type = ntohs(eh->h_proto);
  
        if (type == ETH_P_PAE)
-               atomic_dec(&drvr_priv->pend_8021x_cnt);
+               atomic_dec(&drvr->pend_8021x_cnt);
  
  }
  
  static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
  {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_info *drvr_priv = ifp->info;
+       struct brcmf_bus *bus_if = ifp->drvr->bus_if;
  
        brcmf_dbg(TRACE, "Enter\n");
  
-       if (drvr_priv->pub.up)
-               /* Use the protocol to get dongle stats */
-               brcmf_proto_dstats(&drvr_priv->pub);
        /* Copy dongle stats to net device stats */
-       ifp->stats.rx_packets = drvr_priv->pub.dstats.rx_packets;
-       ifp->stats.tx_packets = drvr_priv->pub.dstats.tx_packets;
-       ifp->stats.rx_bytes = drvr_priv->pub.dstats.rx_bytes;
-       ifp->stats.tx_bytes = drvr_priv->pub.dstats.tx_bytes;
-       ifp->stats.rx_errors = drvr_priv->pub.dstats.rx_errors;
-       ifp->stats.tx_errors = drvr_priv->pub.dstats.tx_errors;
-       ifp->stats.rx_dropped = drvr_priv->pub.dstats.rx_dropped;
-       ifp->stats.tx_dropped = drvr_priv->pub.dstats.tx_dropped;
-       ifp->stats.multicast = drvr_priv->pub.dstats.multicast;
+       ifp->stats.rx_packets = bus_if->dstats.rx_packets;
+       ifp->stats.tx_packets = bus_if->dstats.tx_packets;
+       ifp->stats.rx_bytes = bus_if->dstats.rx_bytes;
+       ifp->stats.tx_bytes = bus_if->dstats.tx_bytes;
+       ifp->stats.rx_errors = bus_if->dstats.rx_errors;
+       ifp->stats.tx_errors = bus_if->dstats.tx_errors;
+       ifp->stats.rx_dropped = bus_if->dstats.rx_dropped;
+       ifp->stats.tx_dropped = bus_if->dstats.tx_dropped;
+       ifp->stats.multicast = bus_if->dstats.multicast;
  
        return &ifp->stats;
  }
  
  /* Retrieve current toe component enables, which are kept
         as a bitmap in toe_ol iovar */
- static int brcmf_toe_get(struct brcmf_info *drvr_priv, int ifidx, u32 *toe_ol)
+ static int brcmf_toe_get(struct brcmf_pub *drvr, int ifidx, u32 *toe_ol)
  {
        struct brcmf_dcmd dcmd;
        __le32 toe_le;
        dcmd.set = false;
  
        strcpy(buf, "toe_ol");
-       ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
+       ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
        if (ret < 0) {
                /* Check for older dongle image that doesn't support toe_ol */
                if (ret == -EIO) {
                        brcmf_dbg(ERROR, "%s: toe not supported by device\n",
-                                 brcmf_ifname(&drvr_priv->pub, ifidx));
+                                 brcmf_ifname(drvr, ifidx));
                        return -EOPNOTSUPP;
                }
  
                brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n",
-                         brcmf_ifname(&drvr_priv->pub, ifidx), ret);
+                         brcmf_ifname(drvr, ifidx), ret);
                return ret;
        }
  
  
  /* Set current toe component enables in toe_ol iovar,
         and set toe global enable iovar */
- static int brcmf_toe_set(struct brcmf_info *drvr_priv, int ifidx, u32 toe_ol)
+ static int brcmf_toe_set(struct brcmf_pub *drvr, int ifidx, u32 toe_ol)
  {
        struct brcmf_dcmd dcmd;
        char buf[32];
        strcpy(buf, "toe_ol");
        memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32));
  
-       ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
+       ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
        if (ret < 0) {
                brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n",
-                         brcmf_ifname(&drvr_priv->pub, ifidx), ret);
+                         brcmf_ifname(drvr, ifidx), ret);
                return ret;
        }
  
        strcpy(buf, "toe");
        memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32));
  
-       ret = brcmf_proto_dcmd(&drvr_priv->pub, ifidx, &dcmd, dcmd.len);
+       ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
        if (ret < 0) {
                brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n",
-                         brcmf_ifname(&drvr_priv->pub, ifidx), ret);
+                         brcmf_ifname(drvr, ifidx), ret);
                return ret;
        }
  
@@@ -604,18 -583,18 +583,18 @@@ static void brcmf_ethtool_get_drvinfo(s
                                    struct ethtool_drvinfo *info)
  {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_info *drvr_priv = ifp->info;
+       struct brcmf_pub *drvr = ifp->drvr;
  
        sprintf(info->driver, KBUILD_MODNAME);
-       sprintf(info->version, "%lu", drvr_priv->pub.drv_version);
-       sprintf(info->bus_info, "%s", dev_name(drvr_priv->pub.dev));
+       sprintf(info->version, "%lu", drvr->drv_version);
+       sprintf(info->bus_info, "%s", dev_name(drvr->dev));
  }
  
  static struct ethtool_ops brcmf_ethtool_ops = {
        .get_drvinfo = brcmf_ethtool_get_drvinfo
  };
  
- static int brcmf_ethtool(struct brcmf_info *drvr_priv, void __user *uaddr)
+ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
  {
        struct ethtool_drvinfo info;
        char drvname[sizeof(info.driver)];
                }
  
                /* otherwise, require dongle to be up */
-               else if (!drvr_priv->pub.up) {
+               else if (!drvr->bus_if->drvr_up) {
                        brcmf_dbg(ERROR, "dongle is not up\n");
                        return -ENODEV;
                }
  
                /* finally, report dongle driver type */
-               else if (drvr_priv->pub.iswl)
+               else if (drvr->iswl)
                        sprintf(info.driver, "wl");
                else
                        sprintf(info.driver, "xx");
  
-               sprintf(info.version, "%lu", drvr_priv->pub.drv_version);
+               sprintf(info.version, "%lu", drvr->drv_version);
                if (copy_to_user(uaddr, &info, sizeof(info)))
                        return -EFAULT;
                brcmf_dbg(CTL, "given %*s, returning %s\n",
                /* Get toe offload components from dongle */
        case ETHTOOL_GRXCSUM:
        case ETHTOOL_GTXCSUM:
-               ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt);
+               ret = brcmf_toe_get(drvr, 0, &toe_cmpnt);
                if (ret < 0)
                        return ret;
  
                        return -EFAULT;
  
                /* Read the current settings, update and write back */
-               ret = brcmf_toe_get(drvr_priv, 0, &toe_cmpnt);
+               ret = brcmf_toe_get(drvr, 0, &toe_cmpnt);
                if (ret < 0)
                        return ret;
  
                else
                        toe_cmpnt &= ~csum_dir;
  
-               ret = brcmf_toe_set(drvr_priv, 0, toe_cmpnt);
+               ret = brcmf_toe_set(drvr, 0, toe_cmpnt);
                if (ret < 0)
                        return ret;
  
                /* If setting TX checksum mode, tell Linux the new mode */
                if (cmd == ETHTOOL_STXCSUM) {
                        if (edata.data)
-                               drvr_priv->iflist[0]->ndev->features |=
+                               drvr->iflist[0]->ndev->features |=
                                    NETIF_F_IP_CSUM;
                        else
-                               drvr_priv->iflist[0]->ndev->features &=
+                               drvr->iflist[0]->ndev->features &=
                                    ~NETIF_F_IP_CSUM;
                }
  
@@@ -730,15 -709,15 +709,15 @@@ static int brcmf_netdev_ioctl_entry(str
                                    int cmd)
  {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_info *drvr_priv = ifp->info;
+       struct brcmf_pub *drvr = ifp->drvr;
  
        brcmf_dbg(TRACE, "ifidx %d, cmd 0x%04x\n", ifp->idx, cmd);
  
-       if (!drvr_priv->iflist[ifp->idx])
+       if (!drvr->iflist[ifp->idx])
                return -1;
  
        if (cmd == SIOCETHTOOL)
-               return brcmf_ethtool(drvr_priv, ifr->ifr_data);
+               return brcmf_ethtool(drvr, ifr->ifr_data);
  
        return -EOPNOTSUPP;
  }
@@@ -751,7 -730,7 +730,7 @@@ s32 brcmf_exec_dcmd(struct net_device *
        int buflen = 0;
        bool is_set_key_cmd;
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_info *drvr_priv = ifp->info;
+       struct brcmf_pub *drvr = ifp->drvr;
  
        memset(&dcmd, 0, sizeof(dcmd));
        dcmd.cmd = cmd;
                buflen = min_t(uint, dcmd.len, BRCMF_DCMD_MAXLEN);
  
        /* send to dongle (must be up, and wl) */
-       if ((drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA)) {
+       if ((drvr->bus_if->state != BRCMF_BUS_DATA)) {
                brcmf_dbg(ERROR, "DONGLE_DOWN\n");
                err = -EIO;
                goto done;
        }
  
-       if (!drvr_priv->pub.iswl) {
+       if (!drvr->iswl) {
                err = -EIO;
                goto done;
        }
        if (is_set_key_cmd)
                brcmf_netdev_wait_pend8021x(ndev);
  
-       err = brcmf_proto_dcmd(&drvr_priv->pub, ifp->idx, &dcmd, buflen);
+       err = brcmf_proto_dcmd(drvr, ifp->idx, &dcmd, buflen);
  
  done:
        if (err > 0)
  static int brcmf_netdev_stop(struct net_device *ndev)
  {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_pub *drvr = &ifp->info->pub;
+       struct brcmf_pub *drvr = ifp->drvr;
  
        brcmf_dbg(TRACE, "Enter\n");
        brcmf_cfg80211_down(drvr->config);
-       if (drvr->up == 0)
+       if (drvr->bus_if->drvr_up == 0)
                return 0;
  
        /* Set state and stop OS transmissions */
-       drvr->up = false;
 -      drvr->bus_if->drvr_up = 0;
++      drvr->bus_if->drvr_up = false;
        netif_stop_queue(ndev);
  
        return 0;
  static int brcmf_netdev_open(struct net_device *ndev)
  {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_info *drvr_priv = ifp->info;
+       struct brcmf_pub *drvr = ifp->drvr;
        u32 toe_ol;
        s32 ret = 0;
  
  
        if (ifp->idx == 0) {    /* do it only for primary eth0 */
                /* try to bring up bus */
-               ret = brcmf_bus_start(&drvr_priv->pub);
+               ret = brcmf_bus_start(drvr->dev);
                if (ret != 0) {
                        brcmf_dbg(ERROR, "failed with code %d\n", ret);
                        return -1;
                }
-               atomic_set(&drvr_priv->pend_8021x_cnt, 0);
+               atomic_set(&drvr->pend_8021x_cnt, 0);
  
-               memcpy(ndev->dev_addr, drvr_priv->pub.mac, ETH_ALEN);
+               memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
  
                /* Get current TOE mode from dongle */
-               if (brcmf_toe_get(drvr_priv, ifp->idx, &toe_ol) >= 0
+               if (brcmf_toe_get(drvr, ifp->idx, &toe_ol) >= 0
                    && (toe_ol & TOE_TX_CSUM_OL) != 0)
-                       drvr_priv->iflist[ifp->idx]->ndev->features |=
+                       drvr->iflist[ifp->idx]->ndev->features |=
                                NETIF_F_IP_CSUM;
                else
-                       drvr_priv->iflist[ifp->idx]->ndev->features &=
+                       drvr->iflist[ifp->idx]->ndev->features &=
                                ~NETIF_F_IP_CSUM;
        }
        /* Allow transmit calls */
        netif_start_queue(ndev);
-       drvr_priv->pub.up = true;
-       if (brcmf_cfg80211_up(drvr_priv->pub.config)) {
 -      drvr->bus_if->drvr_up = 1;
++      drvr->bus_if->drvr_up = true;
+       if (brcmf_cfg80211_up(drvr->config)) {
                brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
                return -1;
        }
@@@ -862,14 -841,16 +841,16 @@@ static const struct net_device_ops brcm
  };
  
  int
- brcmf_add_if(struct brcmf_info *drvr_priv, int ifidx, char *name, u8 *mac_addr)
+ brcmf_add_if(struct device *dev, int ifidx, char *name, u8 *mac_addr)
  {
        struct brcmf_if *ifp;
        struct net_device *ndev;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
  
        brcmf_dbg(TRACE, "idx %d\n", ifidx);
  
-       ifp = drvr_priv->iflist[ifidx];
+       ifp = drvr->iflist[ifidx];
        /*
         * Delete the existing interface before overwriting it
         * in case we missed the BRCMF_E_IF_DEL event.
                netif_stop_queue(ifp->ndev);
                unregister_netdev(ifp->ndev);
                free_netdev(ifp->ndev);
-               drvr_priv->iflist[ifidx] = NULL;
+               drvr->iflist[ifidx] = NULL;
        }
  
        /* Allocate netdev, including space for private structure */
  
        ifp = netdev_priv(ndev);
        ifp->ndev = ndev;
-       ifp->info = drvr_priv;
-       drvr_priv->iflist[ifidx] = ifp;
+       ifp->drvr = drvr;
+       drvr->iflist[ifidx] = ifp;
        ifp->idx = ifidx;
        if (mac_addr != NULL)
                memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
  
-       if (brcmf_net_attach(&drvr_priv->pub, ifp->idx)) {
+       if (brcmf_net_attach(drvr, ifp->idx)) {
                brcmf_dbg(ERROR, "brcmf_net_attach failed");
                free_netdev(ifp->ndev);
-               drvr_priv->iflist[ifidx] = NULL;
+               drvr->iflist[ifidx] = NULL;
                return -EOPNOTSUPP;
        }
  
        return 0;
  }
  
- void brcmf_del_if(struct brcmf_info *drvr_priv, int ifidx)
+ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
  {
        struct brcmf_if *ifp;
  
        brcmf_dbg(TRACE, "idx %d\n", ifidx);
  
-       ifp = drvr_priv->iflist[ifidx];
+       ifp = drvr->iflist[ifidx];
        if (!ifp) {
                brcmf_dbg(ERROR, "Null interface\n");
                return;
                }
  
                unregister_netdev(ifp->ndev);
-               drvr_priv->iflist[ifidx] = NULL;
+               drvr->iflist[ifidx] = NULL;
                if (ifidx == 0)
-                       brcmf_cfg80211_detach(drvr_priv->pub.config);
+                       brcmf_cfg80211_detach(drvr->config);
                free_netdev(ifp->ndev);
        }
  }
  
- struct brcmf_pub *brcmf_attach(struct brcmf_sdio *bus, uint bus_hdrlen,
-                              struct device *dev)
+ int brcmf_attach(uint bus_hdrlen, struct device *dev)
  {
-       struct brcmf_info *drvr_priv = NULL;
+       struct brcmf_pub *drvr = NULL;
+       int ret = 0;
  
        brcmf_dbg(TRACE, "Enter\n");
  
        /* Allocate primary brcmf_info */
-       drvr_priv = kzalloc(sizeof(struct brcmf_info), GFP_ATOMIC);
-       if (!drvr_priv)
-               goto fail;
-       mutex_init(&drvr_priv->proto_block);
+       drvr = kzalloc(sizeof(struct brcmf_pub), GFP_ATOMIC);
+       if (!drvr)
+               return -ENOMEM;
  
-       /* Link to info module */
-       drvr_priv->pub.info = drvr_priv;
+       mutex_init(&drvr->proto_block);
  
        /* Link to bus module */
-       drvr_priv->pub.bus = bus;
-       drvr_priv->pub.hdrlen = bus_hdrlen;
-       drvr_priv->pub.bus_if = dev_get_drvdata(dev);
-       drvr_priv->pub.dev = dev;
+       drvr->hdrlen = bus_hdrlen;
+       drvr->bus_if = dev_get_drvdata(dev);
+       drvr->bus_if->drvr = drvr;
+       drvr->dev = dev;
  
        /* Attach and link in the protocol */
-       if (brcmf_proto_attach(&drvr_priv->pub) != 0) {
+       ret = brcmf_proto_attach(drvr);
+       if (ret != 0) {
                brcmf_dbg(ERROR, "brcmf_prot_attach failed\n");
                goto fail;
        }
  
-       INIT_WORK(&drvr_priv->setmacaddr_work, _brcmf_set_mac_address);
-       INIT_WORK(&drvr_priv->multicast_work, _brcmf_set_multicast_list);
+       INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address);
+       INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list);
  
-       return &drvr_priv->pub;
+       return ret;
  
  fail:
-       if (drvr_priv)
-               brcmf_detach(&drvr_priv->pub);
+       brcmf_detach(dev);
  
-       return NULL;
+       return ret;
  }
  
- int brcmf_bus_start(struct brcmf_pub *drvr)
+ int brcmf_bus_start(struct device *dev)
  {
        int ret = -1;
-       struct brcmf_info *drvr_priv = drvr->info;
        /* Room for "event_msgs" + '\0' + bitvec */
        char iovbuf[BRCMF_EVENTING_MASK_LEN + 12];
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
  
        brcmf_dbg(TRACE, "\n");
  
        /* Bring up the bus */
-       ret = brcmf_sdbrcm_bus_init(drvr_priv->pub.dev);
+       ret = bus_if->brcmf_bus_init(dev);
        if (ret != 0) {
                brcmf_dbg(ERROR, "brcmf_sdbrcm_bus_init failed %d\n", ret);
                return ret;
        }
  
        /* If bus is not ready, can't come up */
-       if (drvr_priv->pub.bus_if->state != BRCMF_BUS_DATA) {
+       if (bus_if->state != BRCMF_BUS_DATA) {
                brcmf_dbg(ERROR, "failed bus is not ready\n");
                return -ENODEV;
        }
        drvr->pktfilter[0] = "100 0 0 0 0x01 0x00";
  
        /* Bus is ready, do any protocol initialization */
-       ret = brcmf_proto_init(&drvr_priv->pub);
+       ret = brcmf_proto_init(drvr);
        if (ret < 0)
                return ret;
  
  
  int brcmf_net_attach(struct brcmf_pub *drvr, int ifidx)
  {
-       struct brcmf_info *drvr_priv = drvr->info;
        struct net_device *ndev;
        u8 temp_addr[ETH_ALEN] = {
                0x00, 0x90, 0x4c, 0x11, 0x22, 0x33};
  
        brcmf_dbg(TRACE, "ifidx %d\n", ifidx);
  
-       ndev = drvr_priv->iflist[ifidx]->ndev;
+       ndev = drvr->iflist[ifidx]->ndev;
        ndev->netdev_ops = &brcmf_netdev_ops_pri;
  
        /*
         */
        if (ifidx != 0) {
                /* for virtual interfaces use the primary MAC  */
-               memcpy(temp_addr, drvr_priv->pub.mac, ETH_ALEN);
+               memcpy(temp_addr, drvr->mac, ETH_ALEN);
  
        }
  
                         - Locally Administered address  */
  
        }
-       ndev->hard_header_len = ETH_HLEN + drvr_priv->pub.hdrlen;
+       ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
        ndev->ethtool_ops = &brcmf_ethtool_ops;
  
-       drvr_priv->pub.rxsz = ndev->mtu + ndev->hard_header_len +
-                             drvr_priv->pub.hdrlen;
+       drvr->rxsz = ndev->mtu + ndev->hard_header_len +
+                             drvr->hdrlen;
  
        memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
  
@@@ -1104,77 -1082,46 +1082,46 @@@ fail
  
  static void brcmf_bus_detach(struct brcmf_pub *drvr)
  {
-       struct brcmf_info *drvr_priv;
        brcmf_dbg(TRACE, "Enter\n");
  
        if (drvr) {
-               drvr_priv = drvr->info;
-               if (drvr_priv) {
-                       /* Stop the protocol module */
-                       brcmf_proto_stop(&drvr_priv->pub);
+               /* Stop the protocol module */
+               brcmf_proto_stop(drvr);
  
-                       /* Stop the bus module */
-                       brcmf_sdbrcm_bus_stop(drvr_priv->pub.dev);
-               }
+               /* Stop the bus module */
+               drvr->bus_if->brcmf_bus_stop(drvr->dev);
        }
  }
  
- void brcmf_detach(struct brcmf_pub *drvr)
+ void brcmf_detach(struct device *dev)
  {
-       struct brcmf_info *drvr_priv;
+       int i;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
  
        brcmf_dbg(TRACE, "Enter\n");
  
-       if (drvr) {
-               drvr_priv = drvr->info;
-               if (drvr_priv) {
-                       int i;
  
-                       /* make sure primary interface removed last */
-                       for (i = BRCMF_MAX_IFS-1; i > -1; i--)
-                               if (drvr_priv->iflist[i])
-                                       brcmf_del_if(drvr_priv, i);
+       /* make sure primary interface removed last */
+       for (i = BRCMF_MAX_IFS-1; i > -1; i--)
+               if (drvr->iflist[i])
+                       brcmf_del_if(drvr, i);
  
-                       cancel_work_sync(&drvr_priv->setmacaddr_work);
-                       cancel_work_sync(&drvr_priv->multicast_work);
+       cancel_work_sync(&drvr->setmacaddr_work);
+       cancel_work_sync(&drvr->multicast_work);
  
-                       brcmf_bus_detach(drvr);
+       brcmf_bus_detach(drvr);
  
-                       if (drvr->prot)
-                               brcmf_proto_detach(drvr);
+       if (drvr->prot)
+               brcmf_proto_detach(drvr);
  
-                       kfree(drvr_priv);
-               }
-       }
- }
- int brcmf_os_proto_block(struct brcmf_pub *drvr)
- {
-       struct brcmf_info *drvr_priv = drvr->info;
-       if (drvr_priv) {
-               mutex_lock(&drvr_priv->proto_block);
-               return 1;
-       }
-       return 0;
- }
- int brcmf_os_proto_unblock(struct brcmf_pub *drvr)
- {
-       struct brcmf_info *drvr_priv = drvr->info;
-       if (drvr_priv) {
-               mutex_unlock(&drvr_priv->proto_block);
-               return 1;
-       }
-       return 0;
+       bus_if->drvr = NULL;
+       kfree(drvr);
  }
  
- static int brcmf_get_pend_8021x_cnt(struct brcmf_info *drvr_priv)
+ static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)
  {
-       return atomic_read(&drvr_priv->pend_8021x_cnt);
+       return atomic_read(&drvr->pend_8021x_cnt);
  }
  
  #define MAX_WAIT_FOR_8021X_TX 10
  int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
  {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_info *drvr_priv = ifp->info;
+       struct brcmf_pub *drvr = ifp->drvr;
        int timeout = 10 * HZ / 1000;
        int ntimes = MAX_WAIT_FOR_8021X_TX;
-       int pend = brcmf_get_pend_8021x_cnt(drvr_priv);
+       int pend = brcmf_get_pend_8021x_cnt(drvr);
  
        while (ntimes && pend) {
                if (pend) {
                        set_current_state(TASK_RUNNING);
                        ntimes--;
                }
-               pend = brcmf_get_pend_8021x_cnt(drvr_priv);
+               pend = brcmf_get_pend_8021x_cnt(drvr);
        }
        return pend;
  }
index 3cf62c363bc00ab43f49d5336f576de928462466,409faea66b8125e0f5ac855968a1acd317730253..cb9da25bd81d9e1fb1ad2855d2915fdf99d2f7a2
@@@ -1044,7 -1044,7 +1044,7 @@@ static void iwl_trans_pcie_stop_device(
  
  static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
                struct iwl_device_cmd *dev_cmd, enum iwl_rxon_context_id ctx,
-               u8 sta_id)
+               u8 sta_id, u8 tid)
  {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
        dma_addr_t txcmd_phys;
        dma_addr_t scratch_phys;
        u16 len, firstlen, secondlen;
-       u16 seq_number = 0;
        u8 wait_write_ptr = 0;
        u8 txq_id;
-       u8 tid = 0;
        bool is_agg = false;
        __le16 fc = hdr->frame_control;
        u8 hdr_len = ieee80211_hdrlen(fc);
+       u16 __maybe_unused wifi_seq;
  
        /*
         * Send this frame after DTIM -- there's a special queue
                txq_id =
                    trans_pcie->ac_to_queue[ctx][skb_get_queue_mapping(skb)];
  
-       if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
-               u8 *qc = NULL;
-               struct iwl_tid_data *tid_data;
-               qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-               tid_data = &trans->shrd->tid_data[sta_id][tid];
-               if (WARN_ON_ONCE(tid >= IWL_MAX_TID_COUNT))
-                       return -1;
-               seq_number = tid_data->seq_number;
-               seq_number &= IEEE80211_SCTL_SEQ;
-               hdr->seq_ctrl = hdr->seq_ctrl &
-                               cpu_to_le16(IEEE80211_SCTL_FRAG);
-               hdr->seq_ctrl |= cpu_to_le16(seq_number);
-               /* aggregation is on for this <sta,tid> */
-               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       if (WARN_ON_ONCE(tid_data->agg.state != IWL_AGG_ON)) {
-                               IWL_ERR(trans, "TX_CTL_AMPDU while not in AGG:"
-                                       " Tx flags = 0x%08x, agg.state = %d",
-                                       info->flags, tid_data->agg.state);
-                               IWL_ERR(trans, "sta_id = %d, tid = %d "
-                                       "txq_id = %d, seq_num = %d", sta_id,
-                                       tid, tid_data->agg.txq_id,
-                                       seq_number >> 4);
-                       }
-                       txq_id = tid_data->agg.txq_id;
-                       is_agg = true;
-               }
-               seq_number += 0x10;
+       /* aggregation is on for this <sta,tid> */
+       if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+               WARN_ON(tid >= IWL_MAX_TID_COUNT);
+               txq_id = trans_pcie->agg_txq[sta_id][tid];
+               is_agg = true;
        }
  
-       /* Copy MAC header from skb into command buffer */
-       memcpy(tx_cmd->hdr, hdr, hdr_len);
        txq = &trans_pcie->txq[txq_id];
        q = &txq->q;
  
+       /* In AGG mode, the index in the ring must correspond to the WiFi
+        * sequence number. This is a HW requirements to help the SCD to parse
+        * the BA.
+        * Check here that the packets are in the right place on the ring.
+        */
+ #ifdef CONFIG_IWLWIFI_DEBUG
+       wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+       WARN_ONCE(is_agg && ((wifi_seq & 0xff) != q->write_ptr),
+                 "Q: %d WiFi Seq %d tfdNum %d",
+                 txq_id, wifi_seq, q->write_ptr);
+ #endif
        /* Set up driver data for this TFD */
        txq->skbs[q->write_ptr] = skb;
        txq->cmd[q->write_ptr] = dev_cmd;
        iwl_print_hex_dump(trans, IWL_DL_TX, (u8 *)tx_cmd->hdr, hdr_len);
  
        /* Set up entry for this TFD in Tx byte-count array */
 -      if (is_agg)
 -              iwl_trans_txq_update_byte_cnt_tbl(trans, txq,
 -                                             le16_to_cpu(tx_cmd->len));
 +      iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
  
        dma_sync_single_for_device(bus(trans)->dev, txcmd_phys, firstlen,
                        DMA_BIDIRECTIONAL);
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
        iwl_txq_update_write_ptr(trans, txq);
  
-       if (ieee80211_is_data_qos(fc) && !ieee80211_is_qos_nullfunc(fc)) {
-               trans->shrd->tid_data[sta_id][tid].tfds_in_queue++;
-               if (!ieee80211_has_morefrags(fc))
-                       trans->shrd->tid_data[sta_id][tid].seq_number =
-                               seq_number;
-       }
        /*
         * At this point the frame is "transmitted" successfully
         * and we will get a TX status notification eventually,
@@@ -1275,85 -1253,30 +1251,30 @@@ static int iwl_trans_pcie_request_irq(s
        return 0;
  }
  
- static int iwlagn_txq_check_empty(struct iwl_trans *trans,
-                          int sta_id, u8 tid, int txq_id)
- {
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_queue *q = &trans_pcie->txq[txq_id].q;
-       struct iwl_tid_data *tid_data = &trans->shrd->tid_data[sta_id][tid];
-       lockdep_assert_held(&trans->shrd->sta_lock);
-       switch (trans->shrd->tid_data[sta_id][tid].agg.state) {
-       case IWL_EMPTYING_HW_QUEUE_DELBA:
-               /* We are reclaiming the last packet of the */
-               /* aggregated HW queue */
-               if ((txq_id  == tid_data->agg.txq_id) &&
-                   (q->read_ptr == q->write_ptr)) {
-                       IWL_DEBUG_TX_QUEUES(trans,
-                               "HW queue empty: continue DELBA flow\n");
-                       iwl_trans_pcie_txq_agg_disable(trans, txq_id);
-                       tid_data->agg.state = IWL_AGG_OFF;
-                       iwl_stop_tx_ba_trans_ready(priv(trans),
-                                                  NUM_IWL_RXON_CTX,
-                                                  sta_id, tid);
-                       iwl_wake_queue(trans, &trans_pcie->txq[txq_id],
-                                      "DELBA flow complete");
-               }
-               break;
-       case IWL_EMPTYING_HW_QUEUE_ADDBA:
-               /* We are reclaiming the last packet of the queue */
-               if (tid_data->tfds_in_queue == 0) {
-                       IWL_DEBUG_TX_QUEUES(trans,
-                               "HW queue empty: continue ADDBA flow\n");
-                       tid_data->agg.state = IWL_AGG_ON;
-                       iwl_start_tx_ba_trans_ready(priv(trans),
-                                                   NUM_IWL_RXON_CTX,
-                                                   sta_id, tid);
-               }
-               break;
-       default:
-               break;
-       }
-       return 0;
- }
- static void iwl_free_tfds_in_queue(struct iwl_trans *trans,
-                           int sta_id, int tid, int freed)
- {
-       lockdep_assert_held(&trans->shrd->sta_lock);
-       if (trans->shrd->tid_data[sta_id][tid].tfds_in_queue >= freed)
-               trans->shrd->tid_data[sta_id][tid].tfds_in_queue -= freed;
-       else {
-               IWL_DEBUG_TX(trans, "free more than tfds_in_queue (%u:%d)\n",
-                       trans->shrd->tid_data[sta_id][tid].tfds_in_queue,
-                       freed);
-               trans->shrd->tid_data[sta_id][tid].tfds_in_queue = 0;
-       }
- }
- static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
+ static int iwl_trans_pcie_reclaim(struct iwl_trans *trans, int sta_id, int tid,
                      int txq_id, int ssn, u32 status,
                      struct sk_buff_head *skbs)
  {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       enum iwl_agg_state agg_state;
        /* n_bd is usually 256 => n_bd - 1 = 0xff */
        int tfd_num = ssn & (txq->q.n_bd - 1);
        int freed = 0;
-       bool cond;
  
        txq->time_stamp = jiffies;
  
-       if (txq->sched_retry) {
-               agg_state =
-                       trans->shrd->tid_data[txq->sta_id][txq->tid].agg.state;
-               cond = (agg_state != IWL_EMPTYING_HW_QUEUE_DELBA);
-       } else {
-               cond = (status != TX_STATUS_FAIL_PASSIVE_NO_RX);
+       if (unlikely(txq_id >= IWLAGN_FIRST_AMPDU_QUEUE &&
+                    txq_id != trans_pcie->agg_txq[sta_id][tid])) {
+               /*
+                * FIXME: this is a uCode bug which need to be addressed,
+                * log the information and return for now.
+                * Since it is can possibly happen very often and in order
+                * not to fill the syslog, don't use IWL_ERR or IWL_WARN
+                */
+               IWL_DEBUG_TX_QUEUES(trans, "Bad queue mapping txq_id %d, "
+                       "agg_txq[sta_id[tid] %d", txq_id,
+                       trans_pcie->agg_txq[sta_id][tid]);
+               return 1;
        }
  
        if (txq->q.read_ptr != tfd_num) {
                                txq_id, iwl_get_queue_ac(txq), txq->q.read_ptr,
                                tfd_num, ssn);
                freed = iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
-               if (iwl_queue_space(&txq->q) > txq->q.low_mark && cond)
+               if (iwl_queue_space(&txq->q) > txq->q.low_mark &&
+                  (!txq->sched_retry ||
+                  status != TX_STATUS_FAIL_PASSIVE_NO_RX))
                        iwl_wake_queue(trans, txq, "Packets reclaimed");
        }
-       iwl_free_tfds_in_queue(trans, sta_id, tid, freed);
-       iwlagn_txq_check_empty(trans, sta_id, tid, txq_id);
+       return 0;
  }
  
  static void iwl_trans_pcie_free(struct iwl_trans *trans)
index e75d5c8d62cc712966cca6998e4ab64452331a98,901cd79a061e0dfcbcf498285840afaa15e3e743..036491f08e9b3c2bb7945263b97f1c0b22671d21
@@@ -31,7 -31,7 +31,7 @@@
  #define MWL8K_VERSION "0.12"
  
  /* Module parameters */
 -static unsigned ap_mode_default;
 +static bool ap_mode_default;
  module_param(ap_mode_default, bool, 0);
  MODULE_PARM_DESC(ap_mode_default,
                 "Set to 1 to make ap mode the default instead of sta mode");
@@@ -738,10 -738,10 +738,10 @@@ static int mwl8k_load_firmware(struct i
  
                ready_code = ioread32(priv->regs + MWL8K_HIU_INT_CODE);
                if (ready_code == MWL8K_FWAP_READY) {
 -                      priv->ap_fw = 1;
 +                      priv->ap_fw = true;
                        break;
                } else if (ready_code == MWL8K_FWSTA_READY) {
 -                      priv->ap_fw = 0;
 +                      priv->ap_fw = false;
                        break;
                }
  
@@@ -5044,14 -5044,14 +5044,14 @@@ mwl8k_ampdu_action(struct ieee80211_hw 
                ieee80211_start_tx_ba_cb_irqsafe(vif, addr, tid);
                break;
        case IEEE80211_AMPDU_TX_STOP:
-               if (stream == NULL)
-                       break;
-               if (stream->state == AMPDU_STREAM_ACTIVE) {
-                       spin_unlock(&priv->stream_lock);
-                       mwl8k_destroy_ba(hw, stream);
-                       spin_lock(&priv->stream_lock);
+               if (stream) {
+                       if (stream->state == AMPDU_STREAM_ACTIVE) {
+                               spin_unlock(&priv->stream_lock);
+                               mwl8k_destroy_ba(hw, stream);
+                               spin_lock(&priv->stream_lock);
+                       }
+                       mwl8k_remove_stream(hw, stream);
                }
-               mwl8k_remove_stream(hw, stream);
                ieee80211_stop_tx_ba_cb_irqsafe(vif, addr, tid);
                break;
        case IEEE80211_AMPDU_TX_OPERATIONAL:
@@@ -5517,8 -5517,8 +5517,8 @@@ static int mwl8k_firmware_load_success(
        INIT_LIST_HEAD(&priv->vif_list);
  
        /* Set default radio state and preamble */
 -      priv->radio_on = 0;
 -      priv->radio_short_preamble = 0;
 +      priv->radio_on = false;
 +      priv->radio_short_preamble = false;
  
        /* Finalize join worker */
        INIT_WORK(&priv->finalize_join_worker, mwl8k_finalize_join_worker);
index b1df1a774948ff00326efafedce16c1df820bf39,7d1b6e4ef0783e20dee788eadd62c6e394edec75..ee01d2e883a08ecd7418a71989463bd6d7f66809
@@@ -45,7 -45,7 +45,7 @@@
  /*
   * Allow hardware encryption to be disabled.
   */
 -static int modparam_nohwcrypt;
 +static bool modparam_nohwcrypt;
  module_param_named(nohwcrypt, modparam_nohwcrypt, bool, S_IRUGO);
  MODULE_PARM_DESC(nohwcrypt, "Disable hardware encryption.");
  
@@@ -1159,6 -1159,8 +1159,8 @@@ static struct usb_device_id rt2800usb_d
        { USB_DEVICE(0x7392, 0x7722) },
        /* Encore */
        { USB_DEVICE(0x203d, 0x14a1) },
+       /* Fujitsu Stylistic 550 */
+       { USB_DEVICE(0x1690, 0x0761) },
        /* Gemtek */
        { USB_DEVICE(0x15a9, 0x0010) },
        /* Gigabyte */
index 74c0214367040beb33d4b343c9cc9a53ed75aed9,7c1d82d8d71c01839c8f0ae5b2df07dc6d6876c1..8d6eb0f56c031b7b4b7ac2d43756c88cd9b0f28b
@@@ -396,7 -396,7 +396,7 @@@ void rtl_init_rfkill(struct ieee80211_h
        u8 valid = 0;
  
        /*set init state to on */
 -      rtlpriv->rfkill.rfkill_state = 1;
 +      rtlpriv->rfkill.rfkill_state = true;
        wiphy_rfkill_set_hw_state(hw->wiphy, 0);
  
        radio_state = rtlpriv->cfg->ops->radio_onoff_checking(hw, &valid);
@@@ -449,6 -449,7 +449,7 @@@ int rtl_init_core(struct ieee80211_hw *
        /* <4> locks */
        mutex_init(&rtlpriv->locks.conf_mutex);
        mutex_init(&rtlpriv->locks.ps_mutex);
+       spin_lock_init(&rtlpriv->locks.ips_lock);
        spin_lock_init(&rtlpriv->locks.irq_th_lock);
        spin_lock_init(&rtlpriv->locks.h2c_lock);
        spin_lock_init(&rtlpriv->locks.rf_ps_lock);
index 9b7d60c0bf8062e1df6d35e0567f5b181ffd292c,115969df0c9ef8d6f81f7bd96b35f9e11fe53ffb..cdaf1429fa0b30b6322f31d21f48f5216e51f7d3
@@@ -1488,7 -1488,7 +1488,7 @@@ struct rtl_intf_ops 
  
  struct rtl_mod_params {
        /* default: 0 = using hardware encryption */
 -      int sw_crypto;
 +      bool sw_crypto;
  
        /* default: 0 = DBG_EMERG (0)*/
        int debug;
@@@ -1547,6 -1547,7 +1547,7 @@@ struct rtl_locks 
        struct mutex ps_mutex;
  
        /*spin lock */
+       spinlock_t ips_lock;
        spinlock_t irq_th_lock;
        spinlock_t h2c_lock;
        spinlock_t rf_ps_lock;
index 72632f155e4321552fef5cafdc4f5be9743fddd2,9572cbd12a7af0b8c746f8a22ae6c0984409d84b..68f5891506925f3101389b2afed34900231291c2
@@@ -482,10 -482,11 +482,11 @@@ struct l2cap_chan 
        __u32           remote_acc_lat;
        __u32           remote_flush_to;
  
-       struct timer_list       chan_timer;
-       struct timer_list       retrans_timer;
-       struct timer_list       monitor_timer;
-       struct timer_list       ack_timer;
+       struct delayed_work     chan_timer;
+       struct delayed_work     retrans_timer;
+       struct delayed_work     monitor_timer;
+       struct delayed_work     ack_timer;
        struct sk_buff          *tx_send_head;
        struct sk_buff_head     tx_q;
        struct sk_buff_head     srej_q;
@@@ -521,7 -522,7 +522,7 @@@ struct l2cap_conn 
        __u8            info_state;
        __u8            info_ident;
  
-       struct timer_list info_timer;
+       struct delayed_work info_timer;
  
        spinlock_t      lock;
  
  
        __u8            disc_reason;
  
-       struct timer_list security_timer;
+       struct delayed_work  security_timer;
        struct smp_chan *smp_chan;
  
        struct list_head chan_l;
-       rwlock_t        chan_lock;
+       struct mutex    chan_lock;
  };
  
  #define L2CAP_INFO_CL_MTU_REQ_SENT    0x01
@@@ -594,6 -595,34 +595,34 @@@ enum 
        FLAG_EFS_ENABLE,
  };
  
+ static inline void l2cap_chan_hold(struct l2cap_chan *c)
+ {
+       atomic_inc(&c->refcnt);
+ }
+ static inline void l2cap_chan_put(struct l2cap_chan *c)
+ {
+       if (atomic_dec_and_test(&c->refcnt))
+               kfree(c);
+ }
+ static inline void l2cap_set_timer(struct l2cap_chan *chan,
+                                       struct delayed_work *work, long timeout)
+ {
+       BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
+       if (!__cancel_delayed_work(work))
+               l2cap_chan_hold(chan);
+       schedule_delayed_work(work, timeout);
+ }
+ static inline void l2cap_clear_timer(struct l2cap_chan *chan,
+                                       struct delayed_work *work)
+ {
+       if (__cancel_delayed_work(work))
+               l2cap_chan_put(chan);
+ }
  #define __set_chan_timer(c, t) l2cap_set_timer(c, &c->chan_timer, (t))
  #define __clear_chan_timer(c) l2cap_clear_timer(c, &c->chan_timer)
  #define __set_retrans_timer(c) l2cap_set_timer(c, &c->retrans_timer, \
@@@ -791,7 -820,7 +820,7 @@@ static inline __u8 __ctrl_size(struct l
                return L2CAP_ENH_HDR_SIZE - L2CAP_HDR_SIZE;
  }
  
 -extern int disable_ertm;
 +extern bool disable_ertm;
  
  int l2cap_init_sockets(void);
  void l2cap_cleanup_sockets(void);
@@@ -805,7 -834,8 +834,8 @@@ int l2cap_add_scid(struct l2cap_chan *c
  struct l2cap_chan *l2cap_chan_create(struct sock *sk);
  void l2cap_chan_close(struct l2cap_chan *chan, int reason);
  void l2cap_chan_destroy(struct l2cap_chan *chan);
- int l2cap_chan_connect(struct l2cap_chan *chan);
+ inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid,
+                                                               bdaddr_t *dst);
  int l2cap_chan_send(struct l2cap_chan *chan, struct msghdr *msg, size_t len,
                                                                u32 priority);
  void l2cap_chan_busy(struct l2cap_chan *chan, int busy);
index 918dc09164bac5ca8a372d6cf81533a5cc2d54a9,919e3c0e74aa4c61ff3e920bad6c7c0ae5f5b11f..4221bd256bddfd89e147f1605f0dd334aa042ea6
@@@ -45,7 -45,7 +45,7 @@@
  #include <net/bluetooth/bluetooth.h>
  #include <net/bluetooth/hci_core.h>
  
 -static int enable_le;
 +static bool enable_le;
  
  /* Handle HCI Event packets */
  
@@@ -378,11 -378,8 +378,8 @@@ static void hci_cc_read_voice_setting(s
  
        BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
  
-       if (hdev->notify) {
-               tasklet_disable(&hdev->tx_task);
+       if (hdev->notify)
                hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-               tasklet_enable(&hdev->tx_task);
-       }
  }
  
  static void hci_cc_write_voice_setting(struct hci_dev *hdev, struct sk_buff *skb)
  
        BT_DBG("%s voice setting 0x%04x", hdev->name, setting);
  
-       if (hdev->notify) {
-               tasklet_disable(&hdev->tx_task);
+       if (hdev->notify)
                hdev->notify(hdev, HCI_NOTIFY_VOICE_SETTING);
-               tasklet_enable(&hdev->tx_task);
-       }
  }
  
  static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
@@@ -562,6 -556,9 +556,9 @@@ static void hci_set_le_support(struct h
  
  static void hci_setup(struct hci_dev *hdev)
  {
+       if (hdev->dev_type != HCI_BREDR)
+               return;
        hci_setup_event_mask(hdev);
  
        if (hdev->hci_ver > BLUETOOTH_VER_1_1)
@@@ -773,6 -770,28 +770,28 @@@ static void hci_cc_read_bd_addr(struct 
        hci_req_complete(hdev, HCI_OP_READ_BD_ADDR, rp->status);
  }
  
+ static void hci_cc_read_data_block_size(struct hci_dev *hdev,
+                                                       struct sk_buff *skb)
+ {
+       struct hci_rp_read_data_block_size *rp = (void *) skb->data;
+       BT_DBG("%s status 0x%x", hdev->name, rp->status);
+       if (rp->status)
+               return;
+       hdev->block_mtu = __le16_to_cpu(rp->max_acl_len);
+       hdev->block_len = __le16_to_cpu(rp->block_len);
+       hdev->num_blocks = __le16_to_cpu(rp->num_blocks);
+       hdev->block_cnt = hdev->num_blocks;
+       BT_DBG("%s blk mtu %d cnt %d len %d", hdev->name, hdev->block_mtu,
+                                       hdev->block_cnt, hdev->block_len);
+       hci_req_complete(hdev, HCI_OP_READ_DATA_BLOCK_SIZE, rp->status);
+ }
  static void hci_cc_write_ca_timeout(struct hci_dev *hdev, struct sk_buff *skb)
  {
        __u8 status = *((__u8 *) skb->data);
@@@ -1014,18 -1033,28 +1033,28 @@@ static void hci_cc_le_set_scan_enable(s
        if (!cp)
                return;
  
-       if (cp->enable == 0x01) {
+       switch (cp->enable) {
+       case LE_SCANNING_ENABLED:
                set_bit(HCI_LE_SCAN, &hdev->dev_flags);
  
-               del_timer(&hdev->adv_timer);
+               cancel_delayed_work_sync(&hdev->adv_work);
  
                hci_dev_lock(hdev);
                hci_adv_entries_clear(hdev);
                hci_dev_unlock(hdev);
-       } else if (cp->enable == 0x00) {
+               break;
+       case LE_SCANNING_DISABLED:
                clear_bit(HCI_LE_SCAN, &hdev->dev_flags);
  
-               mod_timer(&hdev->adv_timer, jiffies + ADV_CLEAR_TIMEOUT);
+               cancel_delayed_work_sync(&hdev->adv_work);
+               queue_delayed_work(hdev->workqueue, &hdev->adv_work,
+                                                jiffies + ADV_CLEAR_TIMEOUT);
+               break;
+       default:
+               BT_ERR("Used reserved LE_Scan_Enable param %d", cp->enable);
+               break;
        }
  }
  
@@@ -2022,6 -2051,10 +2051,10 @@@ static inline void hci_cmd_complete_evt
                hci_cc_read_bd_addr(hdev, skb);
                break;
  
+       case HCI_OP_READ_DATA_BLOCK_SIZE:
+               hci_cc_read_data_block_size(hdev, skb);
+               break;
        case HCI_OP_WRITE_CA_TIMEOUT:
                hci_cc_write_ca_timeout(hdev, skb);
                break;
        if (ev->ncmd) {
                atomic_set(&hdev->cmd_cnt, 1);
                if (!skb_queue_empty(&hdev->cmd_q))
-                       tasklet_schedule(&hdev->cmd_task);
+                       queue_work(hdev->workqueue, &hdev->cmd_work);
        }
  }
  
@@@ -2198,7 -2231,7 +2231,7 @@@ static inline void hci_cmd_status_evt(s
        if (ev->ncmd && !test_bit(HCI_RESET, &hdev->flags)) {
                atomic_set(&hdev->cmd_cnt, 1);
                if (!skb_queue_empty(&hdev->cmd_q))
-                       tasklet_schedule(&hdev->cmd_task);
+                       queue_work(hdev->workqueue, &hdev->cmd_work);
        }
  }
  
@@@ -2231,56 -2264,68 +2264,68 @@@ static inline void hci_role_change_evt(
  static inline void hci_num_comp_pkts_evt(struct hci_dev *hdev, struct sk_buff *skb)
  {
        struct hci_ev_num_comp_pkts *ev = (void *) skb->data;
-       __le16 *ptr;
        int i;
  
        skb_pull(skb, sizeof(*ev));
  
        BT_DBG("%s num_hndl %d", hdev->name, ev->num_hndl);
  
+       if (hdev->flow_ctl_mode != HCI_FLOW_CTL_MODE_PACKET_BASED) {
+               BT_ERR("Wrong event for mode %d", hdev->flow_ctl_mode);
+               return;
+       }
        if (skb->len < ev->num_hndl * 4) {
                BT_DBG("%s bad parameters", hdev->name);
                return;
        }
  
-       tasklet_disable(&hdev->tx_task);
-       for (i = 0, ptr = (__le16 *) skb->data; i < ev->num_hndl; i++) {
+       for (i = 0; i < ev->num_hndl; i++) {
+               struct hci_comp_pkts_info *info = &ev->handles[i];
                struct hci_conn *conn;
                __u16  handle, count;
  
-               handle = get_unaligned_le16(ptr++);
-               count  = get_unaligned_le16(ptr++);
+               handle = __le16_to_cpu(info->handle);
+               count  = __le16_to_cpu(info->count);
  
                conn = hci_conn_hash_lookup_handle(hdev, handle);
-               if (conn) {
-                       conn->sent -= count;
-                       if (conn->type == ACL_LINK) {
+               if (!conn)
+                       continue;
+               conn->sent -= count;
+               switch (conn->type) {
+               case ACL_LINK:
+                       hdev->acl_cnt += count;
+                       if (hdev->acl_cnt > hdev->acl_pkts)
+                               hdev->acl_cnt = hdev->acl_pkts;
+                       break;
+               case LE_LINK:
+                       if (hdev->le_pkts) {
+                               hdev->le_cnt += count;
+                               if (hdev->le_cnt > hdev->le_pkts)
+                                       hdev->le_cnt = hdev->le_pkts;
+                       } else {
                                hdev->acl_cnt += count;
                                if (hdev->acl_cnt > hdev->acl_pkts)
                                        hdev->acl_cnt = hdev->acl_pkts;
-                       } else if (conn->type == LE_LINK) {
-                               if (hdev->le_pkts) {
-                                       hdev->le_cnt += count;
-                                       if (hdev->le_cnt > hdev->le_pkts)
-                                               hdev->le_cnt = hdev->le_pkts;
-                               } else {
-                                       hdev->acl_cnt += count;
-                                       if (hdev->acl_cnt > hdev->acl_pkts)
-                                               hdev->acl_cnt = hdev->acl_pkts;
-                               }
-                       } else {
-                               hdev->sco_cnt += count;
-                               if (hdev->sco_cnt > hdev->sco_pkts)
-                                       hdev->sco_cnt = hdev->sco_pkts;
                        }
+                       break;
+               case SCO_LINK:
+                       hdev->sco_cnt += count;
+                       if (hdev->sco_cnt > hdev->sco_pkts)
+                               hdev->sco_cnt = hdev->sco_pkts;
+                       break;
+               default:
+                       BT_ERR("Unknown type %d conn %p", conn->type, conn);
+                       break;
                }
        }
  
-       tasklet_schedule(&hdev->tx_task);
-       tasklet_enable(&hdev->tx_task);
+       queue_work(hdev->workqueue, &hdev->tx_work);
  }
  
  static inline void hci_mode_change_evt(struct hci_dev *hdev, struct sk_buff *skb)
diff --combined net/bluetooth/hci_sock.c
index 78746cfa16598adf3109669ac526f0224e0ffd8f,189a667c293bb3d4f53ec2d33e8dd94432201cce..6d94616af3129b3519c914c3458eb30cad40de05
@@@ -49,7 -49,7 +49,7 @@@
  #include <net/bluetooth/bluetooth.h>
  #include <net/bluetooth/hci_core.h>
  
 -static int enable_mgmt;
 +static bool enable_mgmt;
  
  /* ----- HCI socket interface ----- */
  
@@@ -188,11 -188,11 +188,11 @@@ static int hci_sock_blacklist_add(struc
        if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
                return -EFAULT;
  
-       hci_dev_lock_bh(hdev);
+       hci_dev_lock(hdev);
  
        err = hci_blacklist_add(hdev, &bdaddr);
  
-       hci_dev_unlock_bh(hdev);
+       hci_dev_unlock(hdev);
  
        return err;
  }
@@@ -205,11 -205,11 +205,11 @@@ static int hci_sock_blacklist_del(struc
        if (copy_from_user(&bdaddr, arg, sizeof(bdaddr)))
                return -EFAULT;
  
-       hci_dev_lock_bh(hdev);
+       hci_dev_lock(hdev);
  
        err = hci_blacklist_del(hdev, &bdaddr);
  
-       hci_dev_unlock_bh(hdev);
+       hci_dev_unlock(hdev);
  
        return err;
  }
@@@ -343,8 -343,11 +343,11 @@@ static int hci_sock_bind(struct socket 
        if (haddr.hci_channel > HCI_CHANNEL_CONTROL)
                return -EINVAL;
  
-       if (haddr.hci_channel == HCI_CHANNEL_CONTROL && !enable_mgmt)
-               return -EINVAL;
+       if (haddr.hci_channel == HCI_CHANNEL_CONTROL) {
+               if (!enable_mgmt)
+                       return -EINVAL;
+               set_bit(HCI_PI_MGMT_INIT, &hci_pi(sk)->flags);
+       }
  
        lock_sock(sk);
  
@@@ -535,10 -538,10 +538,10 @@@ static int hci_sock_sendmsg(struct kioc
  
                if (test_bit(HCI_RAW, &hdev->flags) || (ogf == 0x3f)) {
                        skb_queue_tail(&hdev->raw_q, skb);
-                       tasklet_schedule(&hdev->tx_task);
+                       queue_work(hdev->workqueue, &hdev->tx_work);
                } else {
                        skb_queue_tail(&hdev->cmd_q, skb);
-                       tasklet_schedule(&hdev->cmd_task);
+                       queue_work(hdev->workqueue, &hdev->cmd_work);
                }
        } else {
                if (!capable(CAP_NET_RAW)) {
                }
  
                skb_queue_tail(&hdev->raw_q, skb);
-               tasklet_schedule(&hdev->tx_task);
+               queue_work(hdev->workqueue, &hdev->tx_work);
        }
  
        err = len;
index 9bc22e4c4c616249196ebc1b14fb2209c8e7a44f,cd7bb3d7f2b4de657a997a0362b0c03917ba889f..aa78d8c4b93be75f630e1389b4886ffdd4ab3623
@@@ -3,6 -3,7 +3,7 @@@
     Copyright (C) 2000-2001 Qualcomm Incorporated
     Copyright (C) 2009-2010 Gustavo F. Padovan <gustavo@padovan.org>
     Copyright (C) 2010 Google Inc.
+    Copyright (C) 2011 ProFUSION Embedded Systems
  
     Written 2000,2001 by Maxim Krasnyansky <maxk@qualcomm.com>
  
@@@ -56,7 -57,7 +57,7 @@@
  #include <net/bluetooth/l2cap.h>
  #include <net/bluetooth/smp.h>
  
 -int disable_ertm;
 +bool disable_ertm;
  
  static u32 l2cap_feat_mask = L2CAP_FEAT_FIXED_CHAN;
  static u8 l2cap_fixed_chan[8] = { L2CAP_FC_L2CAP, };
@@@ -76,37 -77,38 +77,38 @@@ static int l2cap_ertm_data_rcv(struct s
  
  /* ---- L2CAP channels ---- */
  
- static inline void chan_hold(struct l2cap_chan *c)
- {
-       atomic_inc(&c->refcnt);
- }
- static inline void chan_put(struct l2cap_chan *c)
- {
-       if (atomic_dec_and_test(&c->refcnt))
-               kfree(c);
- }
  static struct l2cap_chan *__l2cap_get_chan_by_dcid(struct l2cap_conn *conn, u16 cid)
  {
-       struct l2cap_chan *c;
+       struct l2cap_chan *c, *r = NULL;
  
-       list_for_each_entry(c, &conn->chan_l, list) {
-               if (c->dcid == cid)
-                       return c;
+       rcu_read_lock();
+       list_for_each_entry_rcu(c, &conn->chan_l, list) {
+               if (c->dcid == cid) {
+                       r = c;
+                       break;
+               }
        }
-       return NULL;
+       rcu_read_unlock();
+       return r;
  }
  
  static struct l2cap_chan *__l2cap_get_chan_by_scid(struct l2cap_conn *conn, u16 cid)
  {
-       struct l2cap_chan *c;
+       struct l2cap_chan *c, *r = NULL;
  
-       list_for_each_entry(c, &conn->chan_l, list) {
-               if (c->scid == cid)
-                       return c;
+       rcu_read_lock();
+       list_for_each_entry_rcu(c, &conn->chan_l, list) {
+               if (c->scid == cid) {
+                       r = c;
+                       break;
+               }
        }
-       return NULL;
+       rcu_read_unlock();
+       return r;
  }
  
  /* Find channel with given SCID.
@@@ -115,34 -117,36 +117,36 @@@ static struct l2cap_chan *l2cap_get_cha
  {
        struct l2cap_chan *c;
  
-       read_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_scid(conn, cid);
        if (c)
-               bh_lock_sock(c->sk);
-       read_unlock(&conn->chan_lock);
+               lock_sock(c->sk);
        return c;
  }
  
  static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
  {
-       struct l2cap_chan *c;
+       struct l2cap_chan *c, *r = NULL;
  
-       list_for_each_entry(c, &conn->chan_l, list) {
-               if (c->ident == ident)
-                       return c;
+       rcu_read_lock();
+       list_for_each_entry_rcu(c, &conn->chan_l, list) {
+               if (c->ident == ident) {
+                       r = c;
+                       break;
+               }
        }
-       return NULL;
+       rcu_read_unlock();
+       return r;
  }
  
  static inline struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn, u8 ident)
  {
        struct l2cap_chan *c;
  
-       read_lock(&conn->chan_lock);
        c = __l2cap_get_chan_by_ident(conn, ident);
        if (c)
-               bh_lock_sock(c->sk);
-       read_unlock(&conn->chan_lock);
+               lock_sock(c->sk);
        return c;
  }
  
@@@ -213,22 -217,6 +217,6 @@@ static u16 l2cap_alloc_cid(struct l2cap
        return 0;
  }
  
- static void l2cap_set_timer(struct l2cap_chan *chan, struct timer_list *timer, long timeout)
- {
-       BT_DBG("chan %p state %d timeout %ld", chan, chan->state, timeout);
-       if (!mod_timer(timer, jiffies + msecs_to_jiffies(timeout)))
-               chan_hold(chan);
- }
- static void l2cap_clear_timer(struct l2cap_chan *chan, struct timer_list *timer)
- {
-       BT_DBG("chan %p state %d", chan, chan->state);
-       if (timer_pending(timer) && del_timer(timer))
-               chan_put(chan);
- }
  static char *state_to_string(int state)
  {
        switch(state) {
@@@ -264,23 -252,16 +252,16 @@@ static void l2cap_state_change(struct l
        chan->ops->state_change(chan->data, state);
  }
  
- static void l2cap_chan_timeout(unsigned long arg)
+ static void l2cap_chan_timeout(struct work_struct *work)
  {
-       struct l2cap_chan *chan = (struct l2cap_chan *) arg;
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       chan_timer.work);
        struct sock *sk = chan->sk;
        int reason;
  
        BT_DBG("chan %p state %d", chan, chan->state);
  
-       bh_lock_sock(sk);
-       if (sock_owned_by_user(sk)) {
-               /* sk is owned by user. Try again later */
-               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
-               bh_unlock_sock(sk);
-               chan_put(chan);
-               return;
-       }
+       lock_sock(sk);
  
        if (chan->state == BT_CONNECTED || chan->state == BT_CONFIG)
                reason = ECONNREFUSED;
  
        l2cap_chan_close(chan, reason);
  
-       bh_unlock_sock(sk);
+       release_sock(sk);
  
        chan->ops->close(chan->data);
-       chan_put(chan);
+       l2cap_chan_put(chan);
  }
  
  struct l2cap_chan *l2cap_chan_create(struct sock *sk)
        list_add(&chan->global_l, &chan_list);
        write_unlock_bh(&chan_list_lock);
  
-       setup_timer(&chan->chan_timer, l2cap_chan_timeout, (unsigned long) chan);
+       INIT_DELAYED_WORK(&chan->chan_timer, l2cap_chan_timeout);
  
        chan->state = BT_OPEN;
  
@@@ -329,10 -310,10 +310,10 @@@ void l2cap_chan_destroy(struct l2cap_ch
        list_del(&chan->global_l);
        write_unlock_bh(&chan_list_lock);
  
-       chan_put(chan);
+       l2cap_chan_put(chan);
  }
  
- static void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
+ static void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
  {
        BT_DBG("conn %p, psm 0x%2.2x, dcid 0x%4.4x", conn,
                        chan->psm, chan->dcid);
        chan->local_acc_lat     = L2CAP_DEFAULT_ACC_LAT;
        chan->local_flush_to    = L2CAP_DEFAULT_FLUSH_TO;
  
-       chan_hold(chan);
+       l2cap_chan_hold(chan);
  
-       list_add(&chan->list, &conn->chan_l);
+       list_add_rcu(&chan->list, &conn->chan_l);
  }
  
  /* Delete channel.
@@@ -390,10 -371,10 +371,10 @@@ static void l2cap_chan_del(struct l2cap
  
        if (conn) {
                /* Delete from channel list */
-               write_lock_bh(&conn->chan_lock);
-               list_del(&chan->list);
-               write_unlock_bh(&conn->chan_lock);
-               chan_put(chan);
+               list_del_rcu(&chan->list);
+               synchronize_rcu();
+               l2cap_chan_put(chan);
  
                chan->conn = NULL;
                hci_conn_put(conn->hcon);
@@@ -707,7 -688,7 +688,7 @@@ static void l2cap_do_start(struct l2cap
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
  
-               mod_timer(&conn->info_timer, jiffies +
+               schedule_delayed_work(&conn->info_timer,
                                        msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
  
                l2cap_send_cmd(conn, conn->info_ident,
@@@ -759,13 -740,13 +740,13 @@@ static void l2cap_send_disconn_req(stru
  /* ---- L2CAP connections ---- */
  static void l2cap_conn_start(struct l2cap_conn *conn)
  {
-       struct l2cap_chan *chan, *tmp;
+       struct l2cap_chan *chan;
  
        BT_DBG("conn %p", conn);
  
-       read_lock(&conn->chan_lock);
+       rcu_read_lock();
  
-       list_for_each_entry_safe(chan, tmp, &conn->chan_l, list) {
+       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
  
                bh_lock_sock(sk);
                                        &chan->conf_state)) {
                                /* l2cap_chan_close() calls list_del(chan)
                                 * so release the lock */
-                               read_unlock(&conn->chan_lock);
                                l2cap_chan_close(chan, ECONNRESET);
-                               read_lock(&conn->chan_lock);
                                bh_unlock_sock(sk);
                                continue;
                        }
                bh_unlock_sock(sk);
        }
  
-       read_unlock(&conn->chan_lock);
+       rcu_read_unlock();
  }
  
  /* Find socket with cid and source bdaddr.
@@@ -898,7 -877,7 +877,7 @@@ static void l2cap_le_conn_ready(struct 
  
        parent = pchan->sk;
  
-       bh_lock_sock(parent);
+       lock_sock(parent);
  
        /* Check for backlog size */
        if (sk_acceptq_is_full(parent)) {
  
        sk = chan->sk;
  
-       write_lock_bh(&conn->chan_lock);
        hci_conn_hold(conn->hcon);
  
        bacpy(&bt_sk(sk)->src, conn->src);
  
        bt_accept_enqueue(parent, sk);
  
-       __l2cap_chan_add(conn, chan);
+       l2cap_chan_add(conn, chan);
  
        __set_chan_timer(chan, sk->sk_sndtimeo);
  
        l2cap_state_change(chan, BT_CONNECTED);
        parent->sk_data_ready(parent, 0);
  
-       write_unlock_bh(&conn->chan_lock);
  clean:
-       bh_unlock_sock(parent);
+       release_sock(parent);
  }
  
  static void l2cap_chan_ready(struct sock *sk)
@@@ -963,9 -938,9 +938,9 @@@ static void l2cap_conn_ready(struct l2c
        if (conn->hcon->out && conn->hcon->type == LE_LINK)
                smp_conn_security(conn, conn->hcon->pending_sec_level);
  
-       read_lock(&conn->chan_lock);
+       rcu_read_lock();
  
-       list_for_each_entry(chan, &conn->chan_l, list) {
+       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
  
                bh_lock_sock(sk);
                bh_unlock_sock(sk);
        }
  
-       read_unlock(&conn->chan_lock);
+       rcu_read_unlock();
  }
  
  /* Notify sockets that we cannot guaranty reliability anymore */
@@@ -995,21 -970,22 +970,22 @@@ static void l2cap_conn_unreliable(struc
  
        BT_DBG("conn %p", conn);
  
-       read_lock(&conn->chan_lock);
+       rcu_read_lock();
  
-       list_for_each_entry(chan, &conn->chan_l, list) {
+       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
  
                if (test_bit(FLAG_FORCE_RELIABLE, &chan->flags))
                        sk->sk_err = err;
        }
  
-       read_unlock(&conn->chan_lock);
+       rcu_read_unlock();
  }
  
- static void l2cap_info_timeout(unsigned long arg)
+ static void l2cap_info_timeout(struct work_struct *work)
  {
-       struct l2cap_conn *conn = (void *) arg;
+       struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+                                                       info_timer.work);
  
        conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
        conn->info_ident = 0;
@@@ -1033,19 -1009,19 +1009,19 @@@ static void l2cap_conn_del(struct hci_c
        /* Kill channels */
        list_for_each_entry_safe(chan, l, &conn->chan_l, list) {
                sk = chan->sk;
-               bh_lock_sock(sk);
+               lock_sock(sk);
                l2cap_chan_del(chan, err);
-               bh_unlock_sock(sk);
+               release_sock(sk);
                chan->ops->close(chan->data);
        }
  
        hci_chan_del(conn->hchan);
  
        if (conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT)
-               del_timer_sync(&conn->info_timer);
+               __cancel_delayed_work(&conn->info_timer);
  
        if (test_and_clear_bit(HCI_CONN_LE_SMP_PEND, &hcon->pend)) {
-               del_timer(&conn->security_timer);
+               __cancel_delayed_work(&conn->security_timer);
                smp_chan_destroy(conn);
        }
  
        kfree(conn);
  }
  
- static void security_timeout(unsigned long arg)
+ static void security_timeout(struct work_struct *work)
  {
-       struct l2cap_conn *conn = (void *) arg;
+       struct l2cap_conn *conn = container_of(work, struct l2cap_conn,
+                                               security_timer.work);
  
        l2cap_conn_del(conn->hcon, ETIMEDOUT);
  }
@@@ -1095,29 -1072,19 +1072,19 @@@ static struct l2cap_conn *l2cap_conn_ad
        conn->feat_mask = 0;
  
        spin_lock_init(&conn->lock);
-       rwlock_init(&conn->chan_lock);
  
        INIT_LIST_HEAD(&conn->chan_l);
  
        if (hcon->type == LE_LINK)
-               setup_timer(&conn->security_timer, security_timeout,
-                                               (unsigned long) conn);
+               INIT_DELAYED_WORK(&conn->security_timer, security_timeout);
        else
-               setup_timer(&conn->info_timer, l2cap_info_timeout,
-                                               (unsigned long) conn);
+               INIT_DELAYED_WORK(&conn->info_timer, l2cap_info_timeout);
  
        conn->disc_reason = HCI_ERROR_REMOTE_USER_TERM;
  
        return conn;
  }
  
- static inline void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan)
- {
-       write_lock_bh(&conn->chan_lock);
-       __l2cap_chan_add(conn, chan);
-       write_unlock_bh(&conn->chan_lock);
- }
  /* ---- Socket interface ---- */
  
  /* Find socket with psm and source bdaddr.
@@@ -1153,11 -1120,10 +1120,10 @@@ static struct l2cap_chan *l2cap_global_
        return c1;
  }
  
- int l2cap_chan_connect(struct l2cap_chan *chan)
+ inline int l2cap_chan_connect(struct l2cap_chan *chan, __le16 psm, u16 cid, bdaddr_t *dst)
  {
        struct sock *sk = chan->sk;
        bdaddr_t *src = &bt_sk(sk)->src;
-       bdaddr_t *dst = &bt_sk(sk)->dst;
        struct l2cap_conn *conn;
        struct hci_conn *hcon;
        struct hci_dev *hdev;
        if (!hdev)
                return -EHOSTUNREACH;
  
-       hci_dev_lock_bh(hdev);
+       hci_dev_lock(hdev);
+       lock_sock(sk);
+       /* PSM must be odd and lsb of upper byte must be 0 */
+       if ((__le16_to_cpu(psm) & 0x0101) != 0x0001 && !cid &&
+                                       chan->chan_type != L2CAP_CHAN_RAW) {
+               err = -EINVAL;
+               goto done;
+       }
+       if (chan->chan_type == L2CAP_CHAN_CONN_ORIENTED && !(psm || cid)) {
+               err = -EINVAL;
+               goto done;
+       }
+       switch (chan->mode) {
+       case L2CAP_MODE_BASIC:
+               break;
+       case L2CAP_MODE_ERTM:
+       case L2CAP_MODE_STREAMING:
+               if (!disable_ertm)
+                       break;
+               /* fall through */
+       default:
+               err = -ENOTSUPP;
+               goto done;
+       }
+       switch (sk->sk_state) {
+       case BT_CONNECT:
+       case BT_CONNECT2:
+       case BT_CONFIG:
+               /* Already connecting */
+               err = 0;
+               goto done;
+       case BT_CONNECTED:
+               /* Already connected */
+               err = -EISCONN;
+               goto done;
+       case BT_OPEN:
+       case BT_BOUND:
+               /* Can connect */
+               break;
+       default:
+               err = -EBADFD;
+               goto done;
+       }
+       /* Set destination address and psm */
+       bacpy(&bt_sk(sk)->dst, src);
+       chan->psm = psm;
+       chan->dcid = cid;
  
        auth_type = l2cap_get_auth_type(chan);
  
        err = 0;
  
  done:
-       hci_dev_unlock_bh(hdev);
+       hci_dev_unlock(hdev);
        hci_dev_put(hdev);
        return err;
  }
@@@ -1251,17 -1272,18 +1272,18 @@@ int __l2cap_wait_ack(struct sock *sk
        return err;
  }
  
- static void l2cap_monitor_timeout(unsigned long arg)
+ static void l2cap_monitor_timeout(struct work_struct *work)
  {
-       struct l2cap_chan *chan = (void *) arg;
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       monitor_timer.work);
        struct sock *sk = chan->sk;
  
        BT_DBG("chan %p", chan);
  
-       bh_lock_sock(sk);
+       lock_sock(sk);
        if (chan->retry_count >= chan->remote_max_tx) {
                l2cap_send_disconn_req(chan->conn, chan, ECONNABORTED);
-               bh_unlock_sock(sk);
+               release_sock(sk);
                return;
        }
  
        __set_monitor_timer(chan);
  
        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-       bh_unlock_sock(sk);
+       release_sock(sk);
  }
  
- static void l2cap_retrans_timeout(unsigned long arg)
+ static void l2cap_retrans_timeout(struct work_struct *work)
  {
-       struct l2cap_chan *chan = (void *) arg;
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       retrans_timer.work);
        struct sock *sk = chan->sk;
  
        BT_DBG("chan %p", chan);
  
-       bh_lock_sock(sk);
+       lock_sock(sk);
        chan->retry_count = 1;
        __set_monitor_timer(chan);
  
        set_bit(CONN_WAIT_F, &chan->conn_state);
  
        l2cap_send_rr_or_rnr(chan, L2CAP_CTRL_POLL);
-       bh_unlock_sock(sk);
+       release_sock(sk);
  }
  
  static void l2cap_drop_acked_frames(struct l2cap_chan *chan)
@@@ -1778,8 -1801,9 +1801,9 @@@ static void l2cap_raw_recv(struct l2cap
  
        BT_DBG("conn %p", conn);
  
-       read_lock(&conn->chan_lock);
-       list_for_each_entry(chan, &conn->chan_l, list) {
+       rcu_read_lock();
+       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
                if (chan->chan_type != L2CAP_CHAN_RAW)
                        continue;
                if (chan->ops->recv(chan->data, nskb))
                        kfree_skb(nskb);
        }
-       read_unlock(&conn->chan_lock);
+       rcu_read_unlock();
  }
  
  /* ---- L2CAP signalling commands ---- */
@@@ -1955,37 -1980,33 +1980,33 @@@ static void l2cap_add_opt_efs(void **pt
                                                        (unsigned long) &efs);
  }
  
- static void l2cap_ack_timeout(unsigned long arg)
+ static void l2cap_ack_timeout(struct work_struct *work)
  {
-       struct l2cap_chan *chan = (void *) arg;
+       struct l2cap_chan *chan = container_of(work, struct l2cap_chan,
+                                                       ack_timer.work);
  
-       bh_lock_sock(chan->sk);
+       BT_DBG("chan %p", chan);
+       lock_sock(chan->sk);
        l2cap_send_ack(chan);
-       bh_unlock_sock(chan->sk);
+       release_sock(chan->sk);
  }
  
  static inline void l2cap_ertm_init(struct l2cap_chan *chan)
  {
-       struct sock *sk = chan->sk;
        chan->expected_ack_seq = 0;
        chan->unacked_frames = 0;
        chan->buffer_seq = 0;
        chan->num_acked = 0;
        chan->frames_sent = 0;
  
-       setup_timer(&chan->retrans_timer, l2cap_retrans_timeout,
-                                                       (unsigned long) chan);
-       setup_timer(&chan->monitor_timer, l2cap_monitor_timeout,
-                                                       (unsigned long) chan);
-       setup_timer(&chan->ack_timer, l2cap_ack_timeout, (unsigned long) chan);
+       INIT_DELAYED_WORK(&chan->retrans_timer, l2cap_retrans_timeout);
+       INIT_DELAYED_WORK(&chan->monitor_timer, l2cap_monitor_timeout);
+       INIT_DELAYED_WORK(&chan->ack_timer, l2cap_ack_timeout);
  
        skb_queue_head_init(&chan->srej_q);
  
        INIT_LIST_HEAD(&chan->srej_l);
-       sk->sk_backlog_rcv = l2cap_ertm_data_rcv;
  }
  
  static inline __u8 l2cap_select_mode(__u8 mode, __u16 remote_feat_mask)
@@@ -2553,7 -2574,7 +2574,7 @@@ static inline int l2cap_command_rej(str
  
        if ((conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_SENT) &&
                                        cmd->ident == conn->info_ident) {
-               del_timer(&conn->info_timer);
+               __cancel_delayed_work(&conn->info_timer);
  
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
                conn->info_ident = 0;
@@@ -2586,7 -2607,7 +2607,7 @@@ static inline int l2cap_connect_req(str
  
        parent = pchan->sk;
  
-       bh_lock_sock(parent);
+       lock_sock(parent);
  
        /* Check if the ACL is secure enough (if not SDP) */
        if (psm != cpu_to_le16(0x0001) &&
  
        sk = chan->sk;
  
-       write_lock_bh(&conn->chan_lock);
        /* Check if we already have channel with that dcid */
        if (__l2cap_get_chan_by_dcid(conn, scid)) {
-               write_unlock_bh(&conn->chan_lock);
                sock_set_flag(sk, SOCK_ZAPPED);
                chan->ops->close(chan->data);
                goto response;
  
        bt_accept_enqueue(parent, sk);
  
-       __l2cap_chan_add(conn, chan);
+       l2cap_chan_add(conn, chan);
  
        dcid = chan->scid;
  
                status = L2CAP_CS_NO_INFO;
        }
  
-       write_unlock_bh(&conn->chan_lock);
  response:
-       bh_unlock_sock(parent);
+       release_sock(parent);
  
  sendresp:
        rsp.scid   = cpu_to_le16(scid);
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_SENT;
                conn->info_ident = l2cap_get_ident(conn);
  
-               mod_timer(&conn->info_timer, jiffies +
+               schedule_delayed_work(&conn->info_timer,
                                        msecs_to_jiffies(L2CAP_INFO_TIMEOUT));
  
                l2cap_send_cmd(conn, conn->info_ident,
@@@ -2745,19 -2761,11 +2761,11 @@@ static inline int l2cap_connect_rsp(str
                break;
  
        default:
-               /* don't delete l2cap channel if sk is owned by user */
-               if (sock_owned_by_user(sk)) {
-                       l2cap_state_change(chan, BT_DISCONN);
-                       __clear_chan_timer(chan);
-                       __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
-                       break;
-               }
                l2cap_chan_del(chan, ECONNREFUSED);
                break;
        }
  
-       bh_unlock_sock(sk);
+       release_sock(sk);
        return 0;
  }
  
@@@ -2879,7 -2887,7 +2887,7 @@@ static inline int l2cap_config_req(stru
        }
  
  unlock:
-       bh_unlock_sock(sk);
+       release_sock(sk);
        return 0;
  }
  
@@@ -2986,7 -2994,7 +2994,7 @@@ static inline int l2cap_config_rsp(stru
        }
  
  done:
-       bh_unlock_sock(sk);
+       release_sock(sk);
        return 0;
  }
  
@@@ -3015,17 -3023,8 +3023,8 @@@ static inline int l2cap_disconnect_req(
  
        sk->sk_shutdown = SHUTDOWN_MASK;
  
-       /* don't delete l2cap channel if sk is owned by user */
-       if (sock_owned_by_user(sk)) {
-               l2cap_state_change(chan, BT_DISCONN);
-               __clear_chan_timer(chan);
-               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
-               bh_unlock_sock(sk);
-               return 0;
-       }
        l2cap_chan_del(chan, ECONNRESET);
-       bh_unlock_sock(sk);
+       release_sock(sk);
  
        chan->ops->close(chan->data);
        return 0;
@@@ -3049,17 -3048,8 +3048,8 @@@ static inline int l2cap_disconnect_rsp(
  
        sk = chan->sk;
  
-       /* don't delete l2cap channel if sk is owned by user */
-       if (sock_owned_by_user(sk)) {
-               l2cap_state_change(chan, BT_DISCONN);
-               __clear_chan_timer(chan);
-               __set_chan_timer(chan, L2CAP_DISC_TIMEOUT);
-               bh_unlock_sock(sk);
-               return 0;
-       }
        l2cap_chan_del(chan, 0);
-       bh_unlock_sock(sk);
+       release_sock(sk);
  
        chan->ops->close(chan->data);
        return 0;
@@@ -3130,7 -3120,7 +3120,7 @@@ static inline int l2cap_information_rsp
                        conn->info_state & L2CAP_INFO_FEAT_MASK_REQ_DONE)
                return 0;
  
-       del_timer(&conn->info_timer);
+       __cancel_delayed_work(&conn->info_timer);
  
        if (result != L2CAP_IR_SUCCESS) {
                conn->info_state |= L2CAP_INFO_FEAT_MASK_REQ_DONE;
@@@ -4247,12 -4237,7 +4237,7 @@@ static inline int l2cap_data_channel(st
                break;
  
        case L2CAP_MODE_ERTM:
-               if (!sock_owned_by_user(sk)) {
-                       l2cap_ertm_data_rcv(sk, skb);
-               } else {
-                       if (sk_add_backlog(sk, skb))
-                               goto drop;
-               }
+               l2cap_ertm_data_rcv(sk, skb);
  
                goto done;
  
@@@ -4302,7 -4287,7 +4287,7 @@@ drop
  
  done:
        if (sk)
-               bh_unlock_sock(sk);
+               release_sock(sk);
  
        return 0;
  }
@@@ -4318,7 -4303,7 +4303,7 @@@ static inline int l2cap_conless_channel
  
        sk = chan->sk;
  
-       bh_lock_sock(sk);
+       lock_sock(sk);
  
        BT_DBG("sk %p, len %d", sk, skb->len);
  
@@@ -4336,7 -4321,7 +4321,7 @@@ drop
  
  done:
        if (sk)
-               bh_unlock_sock(sk);
+               release_sock(sk);
        return 0;
  }
  
@@@ -4351,7 -4336,7 +4336,7 @@@ static inline int l2cap_att_channel(str
  
        sk = chan->sk;
  
-       bh_lock_sock(sk);
+       lock_sock(sk);
  
        BT_DBG("sk %p, len %d", sk, skb->len);
  
@@@ -4369,7 -4354,7 +4354,7 @@@ drop
  
  done:
        if (sk)
-               bh_unlock_sock(sk);
+               release_sock(sk);
        return 0;
  }
  
@@@ -4419,14 -4404,11 +4404,11 @@@ static void l2cap_recv_frame(struct l2c
  
  /* ---- L2CAP interface with lower layer (HCI) ---- */
  
static int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 type)
int l2cap_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
  {
        int exact = 0, lm1 = 0, lm2 = 0;
        struct l2cap_chan *c;
  
-       if (type != ACL_LINK)
-               return -EINVAL;
        BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
  
        /* Find listening sockets and check their link_mode */
        return exact ? lm1 : lm2;
  }
  
static int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
+ int l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
  {
        struct l2cap_conn *conn;
  
        BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
  
-       if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
-               return -EINVAL;
        if (!status) {
                conn = l2cap_conn_add(hcon, status);
                if (conn)
        return 0;
  }
  
static int l2cap_disconn_ind(struct hci_conn *hcon)
+ int l2cap_disconn_ind(struct hci_conn *hcon)
  {
        struct l2cap_conn *conn = hcon->l2cap_data;
  
        BT_DBG("hcon %p", hcon);
  
-       if ((hcon->type != ACL_LINK && hcon->type != LE_LINK) || !conn)
+       if (!conn)
                return HCI_ERROR_REMOTE_USER_TERM;
        return conn->disc_reason;
  }
  
static int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
+ int l2cap_disconn_cfm(struct hci_conn *hcon, u8 reason)
  {
        BT_DBG("hcon %p reason %d", hcon, reason);
  
-       if (!(hcon->type == ACL_LINK || hcon->type == LE_LINK))
-               return -EINVAL;
        l2cap_conn_del(hcon, bt_to_errno(reason));
        return 0;
  }
  
@@@ -4513,7 -4487,7 +4487,7 @@@ static inline void l2cap_check_encrypti
        }
  }
  
static int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
+ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
  {
        struct l2cap_conn *conn = hcon->l2cap_data;
        struct l2cap_chan *chan;
  
        if (hcon->type == LE_LINK) {
                smp_distribute_keys(conn, 0);
-               del_timer(&conn->security_timer);
+               __cancel_delayed_work(&conn->security_timer);
        }
  
-       read_lock(&conn->chan_lock);
+       rcu_read_lock();
  
-       list_for_each_entry(chan, &conn->chan_l, list) {
+       list_for_each_entry_rcu(chan, &conn->chan_l, list) {
                struct sock *sk = chan->sk;
  
                bh_lock_sock(sk);
                bh_unlock_sock(sk);
        }
  
-       read_unlock(&conn->chan_lock);
+       rcu_read_unlock();
  
        return 0;
  }
  
static int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
+ int l2cap_recv_acldata(struct hci_conn *hcon, struct sk_buff *skb, u16 flags)
  {
        struct l2cap_conn *conn = hcon->l2cap_data;
  
                                BT_ERR("Frame exceeding recv MTU (len %d, "
                                                        "MTU %d)", len,
                                                        chan->imtu);
-                               bh_unlock_sock(sk);
+                               release_sock(sk);
                                l2cap_conn_unreliable(conn, ECOMM);
                                goto drop;
                        }
-                       bh_unlock_sock(sk);
+                       release_sock(sk);
                }
  
                /* Allocate skb for the complete frame (with header) */
@@@ -4760,17 -4734,6 +4734,6 @@@ static const struct file_operations l2c
  
  static struct dentry *l2cap_debugfs;
  
- static struct hci_proto l2cap_hci_proto = {
-       .name           = "L2CAP",
-       .id             = HCI_PROTO_L2CAP,
-       .connect_ind    = l2cap_connect_ind,
-       .connect_cfm    = l2cap_connect_cfm,
-       .disconn_ind    = l2cap_disconn_ind,
-       .disconn_cfm    = l2cap_disconn_cfm,
-       .security_cfm   = l2cap_security_cfm,
-       .recv_acldata   = l2cap_recv_acldata
- };
  int __init l2cap_init(void)
  {
        int err;
        if (err < 0)
                return err;
  
-       err = hci_register_proto(&l2cap_hci_proto);
-       if (err < 0) {
-               BT_ERR("L2CAP protocol registration failed");
-               bt_sock_unregister(BTPROTO_L2CAP);
-               goto error;
-       }
        if (bt_debugfs) {
                l2cap_debugfs = debugfs_create_file("l2cap", 0444,
                                        bt_debugfs, NULL, &l2cap_debugfs_fops);
        }
  
        return 0;
- error:
-       l2cap_cleanup_sockets();
-       return err;
  }
  
  void l2cap_exit(void)
  {
        debugfs_remove(l2cap_debugfs);
-       if (hci_unregister_proto(&l2cap_hci_proto) < 0)
-               BT_ERR("L2CAP protocol unregistration failed");
        l2cap_cleanup_sockets();
  }
  
index eac849b935a1c2fd2cea704e26adb1b1373ed450,09a3cbcf794e9cd6297f6a07841381009a44fd9a..501649bf5596d0373d6b6dd3be791dd1345ad33e
@@@ -51,8 -51,8 +51,8 @@@
  
  #define VERSION "1.11"
  
 -static int disable_cfc;
 -static int l2cap_ertm;
 +static bool disable_cfc;
 +static bool l2cap_ertm;
  static int channel_mtu = -1;
  static unsigned int l2cap_mtu = RFCOMM_MAX_L2CAP_MTU;
  
@@@ -65,8 -65,7 +65,7 @@@ static DEFINE_MUTEX(rfcomm_mutex)
  
  static LIST_HEAD(session_list);
  
- static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
-                                                       u32 priority);
+ static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len);
  static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci);
  static int rfcomm_send_disc(struct rfcomm_session *s, u8 dlci);
  static int rfcomm_queue_disc(struct rfcomm_dlc *d);
@@@ -748,32 -747,23 +747,23 @@@ void rfcomm_session_getaddr(struct rfco
  }
  
  /* ---- RFCOMM frame sending ---- */
- static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len,
-                                                       u32 priority)
+ static int rfcomm_send_frame(struct rfcomm_session *s, u8 *data, int len)
  {
-       struct socket *sock = s->sock;
-       struct sock *sk = sock->sk;
        struct kvec iv = { data, len };
        struct msghdr msg;
  
-       BT_DBG("session %p len %d priority %u", s, len, priority);
-       if (sk->sk_priority != priority) {
-               lock_sock(sk);
-               sk->sk_priority = priority;
-               release_sock(sk);
-       }
+       BT_DBG("session %p len %d", s, len);
  
        memset(&msg, 0, sizeof(msg));
  
-       return kernel_sendmsg(sock, &msg, &iv, 1, len);
+       return kernel_sendmsg(s->sock, &msg, &iv, 1, len);
  }
  
  static int rfcomm_send_cmd(struct rfcomm_session *s, struct rfcomm_cmd *cmd)
  {
        BT_DBG("%p cmd %u", s, cmd->ctrl);
  
-       return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd), HCI_PRIO_MAX);
+       return rfcomm_send_frame(s, (void *) cmd, sizeof(*cmd));
  }
  
  static int rfcomm_send_sabm(struct rfcomm_session *s, u8 dlci)
@@@ -829,8 -819,6 +819,6 @@@ static int rfcomm_queue_disc(struct rfc
        if (!skb)
                return -ENOMEM;
  
-       skb->priority = HCI_PRIO_MAX;
        cmd = (void *) __skb_put(skb, sizeof(*cmd));
        cmd->addr = d->addr;
        cmd->ctrl = __ctrl(RFCOMM_DISC, 1);
@@@ -878,7 -866,7 +866,7 @@@ static int rfcomm_send_nsc(struct rfcom
  
        *ptr = __fcs(buf); ptr++;
  
-       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
+       return rfcomm_send_frame(s, buf, ptr - buf);
  }
  
  static int rfcomm_send_pn(struct rfcomm_session *s, int cr, struct rfcomm_dlc *d)
  
        *ptr = __fcs(buf); ptr++;
  
-       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
+       return rfcomm_send_frame(s, buf, ptr - buf);
  }
  
  int rfcomm_send_rpn(struct rfcomm_session *s, int cr, u8 dlci,
  
        *ptr = __fcs(buf); ptr++;
  
-       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
+       return rfcomm_send_frame(s, buf, ptr - buf);
  }
  
  static int rfcomm_send_rls(struct rfcomm_session *s, int cr, u8 dlci, u8 status)
  
        *ptr = __fcs(buf); ptr++;
  
-       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
+       return rfcomm_send_frame(s, buf, ptr - buf);
  }
  
  static int rfcomm_send_msc(struct rfcomm_session *s, int cr, u8 dlci, u8 v24_sig)
  
        *ptr = __fcs(buf); ptr++;
  
-       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
+       return rfcomm_send_frame(s, buf, ptr - buf);
  }
  
  static int rfcomm_send_fcoff(struct rfcomm_session *s, int cr)
  
        *ptr = __fcs(buf); ptr++;
  
-       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
+       return rfcomm_send_frame(s, buf, ptr - buf);
  }
  
  static int rfcomm_send_fcon(struct rfcomm_session *s, int cr)
  
        *ptr = __fcs(buf); ptr++;
  
-       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
+       return rfcomm_send_frame(s, buf, ptr - buf);
  }
  
  static int rfcomm_send_test(struct rfcomm_session *s, int cr, u8 *pattern, int len)
@@@ -1107,7 -1095,7 +1095,7 @@@ static int rfcomm_send_credits(struct r
  
        *ptr = __fcs(buf); ptr++;
  
-       return rfcomm_send_frame(s, buf, ptr - buf, HCI_PRIO_MAX);
+       return rfcomm_send_frame(s, buf, ptr - buf);
  }
  
  static void rfcomm_make_uih(struct sk_buff *skb, u8 addr)
@@@ -1786,8 -1774,7 +1774,7 @@@ static inline int rfcomm_process_tx(str
                return skb_queue_len(&d->tx_queue);
  
        while (d->tx_credits && (skb = skb_dequeue(&d->tx_queue))) {
-               err = rfcomm_send_frame(d->session, skb->data, skb->len,
-                                                       skb->priority);
+               err = rfcomm_send_frame(d->session, skb->data, skb->len);
                if (err < 0) {
                        skb_queue_head(&d->tx_queue, skb);
                        break;
diff --combined net/bluetooth/sco.c
index a0d11b8738317bcfd1a62e6b49d4d84a8b6fdd86,0d59e61d7822fd69790a814cb23b0c09b92b269f..5dc2f2126fac669a2f1b961efb8ce665768da2f2
@@@ -51,7 -51,7 +51,7 @@@
  #include <net/bluetooth/hci_core.h>
  #include <net/bluetooth/sco.h>
  
 -static int disable_esco;
 +static bool disable_esco;
  
  static const struct proto_ops sco_sock_ops;
  
@@@ -189,7 -189,7 +189,7 @@@ static int sco_connect(struct sock *sk
        if (!hdev)
                return -EHOSTUNREACH;
  
-       hci_dev_lock_bh(hdev);
+       hci_dev_lock(hdev);
  
        if (lmp_esco_capable(hdev) && !disable_esco)
                type = ESCO_LINK;
        }
  
  done:
-       hci_dev_unlock_bh(hdev);
+       hci_dev_unlock(hdev);
        hci_dev_put(hdev);
        return err;
  }
@@@ -893,15 -893,12 +893,12 @@@ done
  }
  
  /* ----- SCO interface with lower layer (HCI) ----- */
static int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr, __u8 type)
int sco_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr)
  {
        register struct sock *sk;
        struct hlist_node *node;
        int lm = 0;
  
-       if (type != SCO_LINK && type != ESCO_LINK)
-               return -EINVAL;
        BT_DBG("hdev %s, bdaddr %s", hdev->name, batostr(bdaddr));
  
        /* Find listening sockets */
        return lm;
  }
  
static int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
+ int sco_connect_cfm(struct hci_conn *hcon, __u8 status)
  {
        BT_DBG("hcon %p bdaddr %s status %d", hcon, batostr(&hcon->dst), status);
-       if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
-               return -EINVAL;
        if (!status) {
                struct sco_conn *conn;
  
        return 0;
  }
  
static int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
+ int sco_disconn_cfm(struct hci_conn *hcon, __u8 reason)
  {
        BT_DBG("hcon %p reason %d", hcon, reason);
  
-       if (hcon->type != SCO_LINK && hcon->type != ESCO_LINK)
-               return -EINVAL;
        sco_conn_del(hcon, bt_to_errno(reason));
        return 0;
  }
  
static int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
+ int sco_recv_scodata(struct hci_conn *hcon, struct sk_buff *skb)
  {
        struct sco_conn *conn = hcon->sco_data;
  
@@@ -1028,15 -1017,6 +1017,6 @@@ static const struct net_proto_family sc
        .create = sco_sock_create,
  };
  
- static struct hci_proto sco_hci_proto = {
-       .name           = "SCO",
-       .id             = HCI_PROTO_SCO,
-       .connect_ind    = sco_connect_ind,
-       .connect_cfm    = sco_connect_cfm,
-       .disconn_cfm    = sco_disconn_cfm,
-       .recv_scodata   = sco_recv_scodata
- };
  int __init sco_init(void)
  {
        int err;
                goto error;
        }
  
-       err = hci_register_proto(&sco_hci_proto);
-       if (err < 0) {
-               BT_ERR("SCO protocol registration failed");
-               bt_sock_unregister(BTPROTO_SCO);
-               goto error;
-       }
        if (bt_debugfs) {
                sco_debugfs = debugfs_create_file("sco", 0444,
                                        bt_debugfs, NULL, &sco_debugfs_fops);
@@@ -1081,9 -1054,6 +1054,6 @@@ void __exit sco_exit(void
        if (bt_sock_unregister(BTPROTO_SCO) < 0)
                BT_ERR("SCO socket unregistration failed");
  
-       if (hci_unregister_proto(&sco_hci_proto) < 0)
-               BT_ERR("SCO protocol unregistration failed");
        proto_unregister(&sco_proto);
  }