Merge tag 'wireless-drivers-next-for-davem-2016-05-02' of git://git.kernel.org/pub...
authorDavid S. Miller <davem@davemloft.net>
Tue, 3 May 2016 04:35:16 +0000 (00:35 -0400)
committerDavid S. Miller <davem@davemloft.net>
Tue, 3 May 2016 04:35:16 +0000 (00:35 -0400)
Kalle Valo says:

====================
wireless-drivers patches for 4.7

Major changes:

brcmfmac

* add support for nl80211 BSS_SELECT feature

mwifiex

* add platform specific wakeup interrupt support

ath10k

* implement set_tsf() for 10.2.4 branch
* remove rare MSI range support
* remove deprecated firmware API 1 support

ath9k

* add module parameter to invert LED polarity

wcn36xx

* fixes to get the driver properly working on Dragonboard 410c
====================

Signed-off-by: David S. Miller <davem@davemloft.net>
81 files changed:
Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt [new file with mode: 0644]
MAINTAINERS
drivers/net/wireless/ath/ath10k/ce.c
drivers/net/wireless/ath/ath10k/ce.h
drivers/net/wireless/ath/ath10k/core.c
drivers/net/wireless/ath/ath10k/core.h
drivers/net/wireless/ath/ath10k/debug.c
drivers/net/wireless/ath/ath10k/debug.h
drivers/net/wireless/ath/ath10k/htc.h
drivers/net/wireless/ath/ath10k/htt.c
drivers/net/wireless/ath/ath10k/htt.h
drivers/net/wireless/ath/ath10k/htt_rx.c
drivers/net/wireless/ath/ath10k/htt_tx.c
drivers/net/wireless/ath/ath10k/hw.h
drivers/net/wireless/ath/ath10k/mac.c
drivers/net/wireless/ath/ath10k/mac.h
drivers/net/wireless/ath/ath10k/pci.c
drivers/net/wireless/ath/ath10k/pci.h
drivers/net/wireless/ath/ath10k/swap.c
drivers/net/wireless/ath/ath10k/swap.h
drivers/net/wireless/ath/ath10k/targaddrs.h
drivers/net/wireless/ath/ath10k/testmode.c
drivers/net/wireless/ath/ath10k/thermal.h
drivers/net/wireless/ath/ath10k/txrx.c
drivers/net/wireless/ath/ath10k/wmi-tlv.c
drivers/net/wireless/ath/ath10k/wmi-tlv.h
drivers/net/wireless/ath/ath10k/wmi.c
drivers/net/wireless/ath/ath10k/wmi.h
drivers/net/wireless/ath/ath10k/wow.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/wcn36xx/debug.c
drivers/net/wireless/ath/wcn36xx/hal.h
drivers/net/wireless/ath/wcn36xx/main.c
drivers/net/wireless/ath/wcn36xx/pmc.c
drivers/net/wireless/ath/wcn36xx/smd.c
drivers/net/wireless/ath/wcn36xx/smd.h
drivers/net/wireless/ath/wcn36xx/txrx.c
drivers/net/wireless/ath/wcn36xx/wcn36xx.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bcdc.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/bus.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/cfg80211.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/common.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/core.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/firmware.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fweh.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwil.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/fwsignal.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/msgbuf.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/p2p.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/proto.h
drivers/net/wireless/broadcom/brcm80211/brcmfmac/sdio.c
drivers/net/wireless/broadcom/brcm80211/brcmfmac/usb.c
drivers/net/wireless/intel/iwlwifi/iwl-drv.c
drivers/net/wireless/intel/iwlwifi/iwl-fw-file.h
drivers/net/wireless/intersil/prism54/isl_38xx.c
drivers/net/wireless/marvell/mwifiex/cfg80211.c
drivers/net/wireless/marvell/mwifiex/cmdevt.c
drivers/net/wireless/marvell/mwifiex/main.c
drivers/net/wireless/marvell/mwifiex/main.h
drivers/net/wireless/marvell/mwifiex/pcie.c
drivers/net/wireless/marvell/mwifiex/pcie.h
drivers/net/wireless/marvell/mwifiex/scan.c
drivers/net/wireless/marvell/mwifiex/sdio.c
drivers/net/wireless/marvell/mwifiex/sdio.h
drivers/net/wireless/marvell/mwifiex/sta_cmd.c
drivers/net/wireless/marvell/mwifiex/sta_cmdresp.c
drivers/net/wireless/marvell/mwifiex/sta_ioctl.c
drivers/net/wireless/marvell/mwifiex/txrx.c
drivers/net/wireless/marvell/mwifiex/uap_txrx.c
drivers/net/wireless/marvell/mwifiex/usb.c
drivers/net/wireless/ralink/rt2x00/rt2800lib.c
drivers/net/wireless/realtek/rtl818x/rtl8180/dev.c
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.c
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu.h
drivers/net/wireless/realtek/rtl8xxxu/rtl8xxxu_regs.h
drivers/net/wireless/realtek/rtlwifi/rtl8821ae/phy.c

diff --git a/Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt b/Documentation/devicetree/bindings/net/wireless/marvell-sd8xxx.txt
new file mode 100644 (file)
index 0000000..c421aba
--- /dev/null
@@ -0,0 +1,63 @@
+Marvell 8897/8997 (sd8897/sd8997) SDIO devices
+------
+
+This node provides properties for controlling the marvell sdio wireless device.
+The node is expected to be specified as a child node to the SDIO controller that
+connects the device to the system.
+
+Required properties:
+
+  - compatible : should be one of the following:
+       * "marvell,sd8897"
+       * "marvell,sd8997"
+
+Optional properties:
+
+  - marvell,caldata* : A series of properties with marvell,caldata prefix,
+                     represent calibration data downloaded to the device during
+                     initialization. This is an array of unsigned 8-bit values.
+                     the properties should follow below property name and
+                     corresponding array length:
+       "marvell,caldata-txpwrlimit-2g" (length = 566).
+       "marvell,caldata-txpwrlimit-5g-sub0" (length = 502).
+       "marvell,caldata-txpwrlimit-5g-sub1" (length = 688).
+       "marvell,caldata-txpwrlimit-5g-sub2" (length = 750).
+       "marvell,caldata-txpwrlimit-5g-sub3" (length = 502).
+  - marvell,wakeup-pin : a wakeup pin number of wifi chip which will be configured
+                     to firmware. Firmware will wakeup the host using this pin
+                     during suspend/resume.
+  - interrupt-parent: phandle of the parent interrupt controller
+  - interrupts : interrupt pin number to the cpu. driver will request an irq based on
+                this interrupt number. during system suspend, the irq will be enabled
+                so that the wifi chip can wakeup host platform under certain condition.
+                during system resume, the irq will be disabled to make sure
+                unnecessary interrupt is not received.
+
+Example:
+
+Tx power limit calibration data is configured in below example.
+The calibration data is an array of unsigned values, the length
+can vary between hw versions.
+IRQ pin 38 is used as system wakeup source interrupt. wakeup pin 3 is configured
+so that firmware can wakeup host using this device side pin.
+
+&mmc3 {
+       status = "okay";
+       vmmc-supply = <&wlan_en_reg>;
+       bus-width = <4>;
+       cap-power-off-card;
+       keep-power-in-suspend;
+
+       #address-cells = <1>;
+       #size-cells = <0>;
+       mwifiex: wifi@1 {
+               compatible = "marvell,sd8897";
+               reg = <1>;
+               interrupt-parent = <&pio>;
+               interrupts = <38 IRQ_TYPE_LEVEL_LOW>;
+
+               marvell,caldata_00_txpwrlimit_2g_cfg_set = /bits/ 8 <
+       0x01 0x00 0x06 0x00 0x08 0x02 0x89 0x01>;
+               marvell,wakeup-pin = <3>;
+       };
+};
index fa02825..ab00801 100644 (file)
@@ -9490,7 +9490,7 @@ F:        drivers/net/wireless/realtek/rtlwifi/rtl8192ce/
 RTL8XXXU WIRELESS DRIVER (rtl8xxxu)
 M:     Jes Sorensen <Jes.Sorensen@redhat.com>
 L:     linux-wireless@vger.kernel.org
-T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8723au-mac80211
+T:     git git://git.kernel.org/pub/scm/linux/kernel/git/jes/linux.git rtl8xxxu-devel
 S:     Maintained
 F:     drivers/net/wireless/realtek/rtl8xxxu/
 
index 7212802..9fb8d74 100644 (file)
@@ -1050,11 +1050,11 @@ int ath10k_ce_alloc_pipe(struct ath10k *ar, int ce_id,
         *
         * For the lack of a better place do the check here.
         */
-       BUILD_BUG_ON(2*TARGET_NUM_MSDU_DESC >
+       BUILD_BUG_ON(2 * TARGET_NUM_MSDU_DESC >
                     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
-       BUILD_BUG_ON(2*TARGET_10X_NUM_MSDU_DESC >
+       BUILD_BUG_ON(2 * TARGET_10X_NUM_MSDU_DESC >
                     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
-       BUILD_BUG_ON(2*TARGET_TLV_NUM_MSDU_DESC >
+       BUILD_BUG_ON(2 * TARGET_TLV_NUM_MSDU_DESC >
                     (CE_HTT_H2T_MSG_SRC_NENTRIES - 1));
 
        ce_state->ar = ar;
index 25cafcf..dfc0986 100644 (file)
@@ -408,7 +408,7 @@ static inline u32 ath10k_ce_base_address(struct ath10k *ar, unsigned int ce_id)
 
 /* Ring arithmetic (modulus number of entries in ring, which is a pwr of 2). */
 #define CE_RING_DELTA(nentries_mask, fromidx, toidx) \
-       (((int)(toidx)-(int)(fromidx)) & (nentries_mask))
+       (((int)(toidx) - (int)(fromidx)) & (nentries_mask))
 
 #define CE_RING_IDX_INCR(nentries_mask, idx) (((idx) + 1) & (nentries_mask))
 #define CE_RING_IDX_ADD(nentries_mask, idx, num) \
index b2c7fe3..e94cb87 100644 (file)
@@ -63,8 +63,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .cal_data_len = 2116,
                .fw = {
                        .dir = QCA988X_HW_2_0_FW_DIR,
-                       .fw = QCA988X_HW_2_0_FW_FILE,
-                       .otp = QCA988X_HW_2_0_OTP_FILE,
                        .board = QCA988X_HW_2_0_BOARD_DATA_FILE,
                        .board_size = QCA988X_BOARD_DATA_SZ,
                        .board_ext_size = QCA988X_BOARD_EXT_DATA_SZ,
@@ -82,8 +80,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .cal_data_len = 8124,
                .fw = {
                        .dir = QCA6174_HW_2_1_FW_DIR,
-                       .fw = QCA6174_HW_2_1_FW_FILE,
-                       .otp = QCA6174_HW_2_1_OTP_FILE,
                        .board = QCA6174_HW_2_1_BOARD_DATA_FILE,
                        .board_size = QCA6174_BOARD_DATA_SZ,
                        .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
@@ -102,8 +98,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .cal_data_len = 8124,
                .fw = {
                        .dir = QCA6174_HW_2_1_FW_DIR,
-                       .fw = QCA6174_HW_2_1_FW_FILE,
-                       .otp = QCA6174_HW_2_1_OTP_FILE,
                        .board = QCA6174_HW_2_1_BOARD_DATA_FILE,
                        .board_size = QCA6174_BOARD_DATA_SZ,
                        .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
@@ -122,8 +116,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .cal_data_len = 8124,
                .fw = {
                        .dir = QCA6174_HW_3_0_FW_DIR,
-                       .fw = QCA6174_HW_3_0_FW_FILE,
-                       .otp = QCA6174_HW_3_0_OTP_FILE,
                        .board = QCA6174_HW_3_0_BOARD_DATA_FILE,
                        .board_size = QCA6174_BOARD_DATA_SZ,
                        .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
@@ -143,8 +135,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .fw = {
                        /* uses same binaries as hw3.0 */
                        .dir = QCA6174_HW_3_0_FW_DIR,
-                       .fw = QCA6174_HW_3_0_FW_FILE,
-                       .otp = QCA6174_HW_3_0_OTP_FILE,
                        .board = QCA6174_HW_3_0_BOARD_DATA_FILE,
                        .board_size = QCA6174_BOARD_DATA_SZ,
                        .board_ext_size = QCA6174_BOARD_EXT_DATA_SZ,
@@ -167,8 +157,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .cal_data_len = 12064,
                .fw = {
                        .dir = QCA99X0_HW_2_0_FW_DIR,
-                       .fw = QCA99X0_HW_2_0_FW_FILE,
-                       .otp = QCA99X0_HW_2_0_OTP_FILE,
                        .board = QCA99X0_HW_2_0_BOARD_DATA_FILE,
                        .board_size = QCA99X0_BOARD_DATA_SZ,
                        .board_ext_size = QCA99X0_BOARD_EXT_DATA_SZ,
@@ -186,8 +174,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .cal_data_len = 8124,
                .fw = {
                        .dir = QCA9377_HW_1_0_FW_DIR,
-                       .fw = QCA9377_HW_1_0_FW_FILE,
-                       .otp = QCA9377_HW_1_0_OTP_FILE,
                        .board = QCA9377_HW_1_0_BOARD_DATA_FILE,
                        .board_size = QCA9377_BOARD_DATA_SZ,
                        .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
@@ -205,8 +191,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .cal_data_len = 8124,
                .fw = {
                        .dir = QCA9377_HW_1_0_FW_DIR,
-                       .fw = QCA9377_HW_1_0_FW_FILE,
-                       .otp = QCA9377_HW_1_0_OTP_FILE,
                        .board = QCA9377_HW_1_0_BOARD_DATA_FILE,
                        .board_size = QCA9377_BOARD_DATA_SZ,
                        .board_ext_size = QCA9377_BOARD_EXT_DATA_SZ,
@@ -229,8 +213,6 @@ static const struct ath10k_hw_params ath10k_hw_params_list[] = {
                .cal_data_len = 12064,
                .fw = {
                        .dir = QCA4019_HW_1_0_FW_DIR,
-                       .fw = QCA4019_HW_1_0_FW_FILE,
-                       .otp = QCA4019_HW_1_0_OTP_FILE,
                        .board = QCA4019_HW_1_0_BOARD_DATA_FILE,
                        .board_size = QCA4019_BOARD_DATA_SZ,
                        .board_ext_size = QCA4019_BOARD_EXT_DATA_SZ,
@@ -279,7 +261,7 @@ void ath10k_core_get_fw_features_str(struct ath10k *ar,
        int i;
 
        for (i = 0; i < ATH10K_FW_FEATURE_COUNT; i++) {
-               if (test_bit(i, ar->fw_features)) {
+               if (test_bit(i, ar->normal_mode_fw.fw_file.fw_features)) {
                        if (len > 0)
                                len += scnprintf(buf + len, buf_len - len, ",");
 
@@ -556,7 +538,8 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)
 
        address = ar->hw_params.patch_load_addr;
 
-       if (!ar->otp_data || !ar->otp_len) {
+       if (!ar->normal_mode_fw.fw_file.otp_data ||
+           !ar->normal_mode_fw.fw_file.otp_len) {
                ath10k_warn(ar,
                            "failed to retrieve board id because of invalid otp\n");
                return -ENODATA;
@@ -564,9 +547,11 @@ static int ath10k_core_get_board_id_from_otp(struct ath10k *ar)
 
        ath10k_dbg(ar, ATH10K_DBG_BOOT,
                   "boot upload otp to 0x%x len %zd for board id\n",
-                  address, ar->otp_len);
+                  address, ar->normal_mode_fw.fw_file.otp_len);
 
-       ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
+       ret = ath10k_bmi_fast_download(ar, address,
+                                      ar->normal_mode_fw.fw_file.otp_data,
+                                      ar->normal_mode_fw.fw_file.otp_len);
        if (ret) {
                ath10k_err(ar, "could not write otp for board id check: %d\n",
                           ret);
@@ -604,7 +589,9 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
        u32 bmi_otp_exe_param = ar->hw_params.otp_exe_param;
        int ret;
 
-       ret = ath10k_download_board_data(ar, ar->board_data, ar->board_len);
+       ret = ath10k_download_board_data(ar,
+                                        ar->running_fw->board_data,
+                                        ar->running_fw->board_len);
        if (ret) {
                ath10k_err(ar, "failed to download board data: %d\n", ret);
                return ret;
@@ -612,16 +599,20 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
 
        /* OTP is optional */
 
-       if (!ar->otp_data || !ar->otp_len) {
+       if (!ar->running_fw->fw_file.otp_data ||
+           !ar->running_fw->fw_file.otp_len) {
                ath10k_warn(ar, "Not running otp, calibration will be incorrect (otp-data %p otp_len %zd)!\n",
-                           ar->otp_data, ar->otp_len);
+                           ar->running_fw->fw_file.otp_data,
+                           ar->running_fw->fw_file.otp_len);
                return 0;
        }
 
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot upload otp to 0x%x len %zd\n",
-                  address, ar->otp_len);
+                  address, ar->running_fw->fw_file.otp_len);
 
-       ret = ath10k_bmi_fast_download(ar, address, ar->otp_data, ar->otp_len);
+       ret = ath10k_bmi_fast_download(ar, address,
+                                      ar->running_fw->fw_file.otp_data,
+                                      ar->running_fw->fw_file.otp_len);
        if (ret) {
                ath10k_err(ar, "could not write otp (%d)\n", ret);
                return ret;
@@ -636,7 +627,7 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot otp execute result %d\n", result);
 
        if (!(skip_otp || test_bit(ATH10K_FW_FEATURE_IGNORE_OTP_RESULT,
-                                  ar->fw_features)) &&
+                                  ar->running_fw->fw_file.fw_features)) &&
            result != 0) {
                ath10k_err(ar, "otp calibration failed: %d", result);
                return -EINVAL;
@@ -645,46 +636,32 @@ static int ath10k_download_and_run_otp(struct ath10k *ar)
        return 0;
 }
 
-static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)
+static int ath10k_download_fw(struct ath10k *ar)
 {
        u32 address, data_len;
-       const char *mode_name;
        const void *data;
        int ret;
 
        address = ar->hw_params.patch_load_addr;
 
-       switch (mode) {
-       case ATH10K_FIRMWARE_MODE_NORMAL:
-               data = ar->firmware_data;
-               data_len = ar->firmware_len;
-               mode_name = "normal";
-               ret = ath10k_swap_code_seg_configure(ar,
-                                                    ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW);
-               if (ret) {
-                       ath10k_err(ar, "failed to configure fw code swap: %d\n",
-                                  ret);
-                       return ret;
-               }
-               break;
-       case ATH10K_FIRMWARE_MODE_UTF:
-               data = ar->testmode.utf_firmware_data;
-               data_len = ar->testmode.utf_firmware_len;
-               mode_name = "utf";
-               break;
-       default:
-               ath10k_err(ar, "unknown firmware mode: %d\n", mode);
-               return -EINVAL;
+       data = ar->running_fw->fw_file.firmware_data;
+       data_len = ar->running_fw->fw_file.firmware_len;
+
+       ret = ath10k_swap_code_seg_configure(ar);
+       if (ret) {
+               ath10k_err(ar, "failed to configure fw code swap: %d\n",
+                          ret);
+               return ret;
        }
 
        ath10k_dbg(ar, ATH10K_DBG_BOOT,
-                  "boot uploading firmware image %p len %d mode %s\n",
-                  data, data_len, mode_name);
+                  "boot uploading firmware image %p len %d\n",
+                  data, data_len);
 
        ret = ath10k_bmi_fast_download(ar, address, data, data_len);
        if (ret) {
-               ath10k_err(ar, "failed to download %s firmware: %d\n",
-                          mode_name, ret);
+               ath10k_err(ar, "failed to download firmware: %d\n",
+                          ret);
                return ret;
        }
 
@@ -693,34 +670,30 @@ static int ath10k_download_fw(struct ath10k *ar, enum ath10k_firmware_mode mode)
 
 static void ath10k_core_free_board_files(struct ath10k *ar)
 {
-       if (!IS_ERR(ar->board))
-               release_firmware(ar->board);
+       if (!IS_ERR(ar->normal_mode_fw.board))
+               release_firmware(ar->normal_mode_fw.board);
 
-       ar->board = NULL;
-       ar->board_data = NULL;
-       ar->board_len = 0;
+       ar->normal_mode_fw.board = NULL;
+       ar->normal_mode_fw.board_data = NULL;
+       ar->normal_mode_fw.board_len = 0;
 }
 
 static void ath10k_core_free_firmware_files(struct ath10k *ar)
 {
-       if (!IS_ERR(ar->otp))
-               release_firmware(ar->otp);
-
-       if (!IS_ERR(ar->firmware))
-               release_firmware(ar->firmware);
+       if (!IS_ERR(ar->normal_mode_fw.fw_file.firmware))
+               release_firmware(ar->normal_mode_fw.fw_file.firmware);
 
        if (!IS_ERR(ar->cal_file))
                release_firmware(ar->cal_file);
 
        ath10k_swap_code_seg_release(ar);
 
-       ar->otp = NULL;
-       ar->otp_data = NULL;
-       ar->otp_len = 0;
+       ar->normal_mode_fw.fw_file.otp_data = NULL;
+       ar->normal_mode_fw.fw_file.otp_len = 0;
 
-       ar->firmware = NULL;
-       ar->firmware_data = NULL;
-       ar->firmware_len = 0;
+       ar->normal_mode_fw.fw_file.firmware = NULL;
+       ar->normal_mode_fw.fw_file.firmware_data = NULL;
+       ar->normal_mode_fw.fw_file.firmware_len = 0;
 
        ar->cal_file = NULL;
 }
@@ -759,14 +732,14 @@ static int ath10k_core_fetch_board_data_api_1(struct ath10k *ar)
                return -EINVAL;
        }
 
-       ar->board = ath10k_fetch_fw_file(ar,
-                                        ar->hw_params.fw.dir,
-                                        ar->hw_params.fw.board);
-       if (IS_ERR(ar->board))
-               return PTR_ERR(ar->board);
+       ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
+                                                       ar->hw_params.fw.dir,
+                                                       ar->hw_params.fw.board);
+       if (IS_ERR(ar->normal_mode_fw.board))
+               return PTR_ERR(ar->normal_mode_fw.board);
 
-       ar->board_data = ar->board->data;
-       ar->board_len = ar->board->size;
+       ar->normal_mode_fw.board_data = ar->normal_mode_fw.board->data;
+       ar->normal_mode_fw.board_len = ar->normal_mode_fw.board->size;
 
        return 0;
 }
@@ -826,8 +799,8 @@ static int ath10k_core_parse_bd_ie_board(struct ath10k *ar,
                                   "boot found board data for '%s'",
                                   boardname);
 
-                       ar->board_data = board_ie_data;
-                       ar->board_len = board_ie_len;
+                       ar->normal_mode_fw.board_data = board_ie_data;
+                       ar->normal_mode_fw.board_len = board_ie_len;
 
                        ret = 0;
                        goto out;
@@ -860,12 +833,14 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
        const u8 *data;
        int ret, ie_id;
 
-       ar->board = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, filename);
-       if (IS_ERR(ar->board))
-               return PTR_ERR(ar->board);
+       ar->normal_mode_fw.board = ath10k_fetch_fw_file(ar,
+                                                       ar->hw_params.fw.dir,
+                                                       filename);
+       if (IS_ERR(ar->normal_mode_fw.board))
+               return PTR_ERR(ar->normal_mode_fw.board);
 
-       data = ar->board->data;
-       len = ar->board->size;
+       data = ar->normal_mode_fw.board->data;
+       len = ar->normal_mode_fw.board->size;
 
        /* magic has extra null byte padded */
        magic_len = strlen(ATH10K_BOARD_MAGIC) + 1;
@@ -932,7 +907,7 @@ static int ath10k_core_fetch_board_data_api_n(struct ath10k *ar,
        }
 
 out:
-       if (!ar->board_data || !ar->board_len) {
+       if (!ar->normal_mode_fw.board_data || !ar->normal_mode_fw.board_len) {
                ath10k_err(ar,
                           "failed to fetch board data for %s from %s/%s\n",
                           boardname, ar->hw_params.fw.dir, filename);
@@ -1000,51 +975,8 @@ success:
        return 0;
 }
 
-static int ath10k_core_fetch_firmware_api_1(struct ath10k *ar)
-{
-       int ret = 0;
-
-       if (ar->hw_params.fw.fw == NULL) {
-               ath10k_err(ar, "firmware file not defined\n");
-               return -EINVAL;
-       }
-
-       ar->firmware = ath10k_fetch_fw_file(ar,
-                                           ar->hw_params.fw.dir,
-                                           ar->hw_params.fw.fw);
-       if (IS_ERR(ar->firmware)) {
-               ret = PTR_ERR(ar->firmware);
-               ath10k_err(ar, "could not fetch firmware (%d)\n", ret);
-               goto err;
-       }
-
-       ar->firmware_data = ar->firmware->data;
-       ar->firmware_len = ar->firmware->size;
-
-       /* OTP may be undefined. If so, don't fetch it at all */
-       if (ar->hw_params.fw.otp == NULL)
-               return 0;
-
-       ar->otp = ath10k_fetch_fw_file(ar,
-                                      ar->hw_params.fw.dir,
-                                      ar->hw_params.fw.otp);
-       if (IS_ERR(ar->otp)) {
-               ret = PTR_ERR(ar->otp);
-               ath10k_err(ar, "could not fetch otp (%d)\n", ret);
-               goto err;
-       }
-
-       ar->otp_data = ar->otp->data;
-       ar->otp_len = ar->otp->size;
-
-       return 0;
-
-err:
-       ath10k_core_free_firmware_files(ar);
-       return ret;
-}
-
-static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
+int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
+                                    struct ath10k_fw_file *fw_file)
 {
        size_t magic_len, len, ie_len;
        int ie_id, i, index, bit, ret;
@@ -1053,15 +985,17 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
        __le32 *timestamp, *version;
 
        /* first fetch the firmware file (firmware-*.bin) */
-       ar->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir, name);
-       if (IS_ERR(ar->firmware)) {
+       fw_file->firmware = ath10k_fetch_fw_file(ar, ar->hw_params.fw.dir,
+                                                name);
+       if (IS_ERR(fw_file->firmware)) {
                ath10k_err(ar, "could not fetch firmware file '%s/%s': %ld\n",
-                          ar->hw_params.fw.dir, name, PTR_ERR(ar->firmware));
-               return PTR_ERR(ar->firmware);
+                          ar->hw_params.fw.dir, name,
+                          PTR_ERR(fw_file->firmware));
+               return PTR_ERR(fw_file->firmware);
        }
 
-       data = ar->firmware->data;
-       len = ar->firmware->size;
+       data = fw_file->firmware->data;
+       len = fw_file->firmware->size;
 
        /* magic also includes the null byte, check that as well */
        magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
@@ -1104,15 +1038,15 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
 
                switch (ie_id) {
                case ATH10K_FW_IE_FW_VERSION:
-                       if (ie_len > sizeof(ar->hw->wiphy->fw_version) - 1)
+                       if (ie_len > sizeof(fw_file->fw_version) - 1)
                                break;
 
-                       memcpy(ar->hw->wiphy->fw_version, data, ie_len);
-                       ar->hw->wiphy->fw_version[ie_len] = '\0';
+                       memcpy(fw_file->fw_version, data, ie_len);
+                       fw_file->fw_version[ie_len] = '\0';
 
                        ath10k_dbg(ar, ATH10K_DBG_BOOT,
                                   "found fw version %s\n",
-                                   ar->hw->wiphy->fw_version);
+                                   fw_file->fw_version);
                        break;
                case ATH10K_FW_IE_TIMESTAMP:
                        if (ie_len != sizeof(u32))
@@ -1139,21 +1073,21 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                                        ath10k_dbg(ar, ATH10K_DBG_BOOT,
                                                   "Enabling feature bit: %i\n",
                                                   i);
-                                       __set_bit(i, ar->fw_features);
+                                       __set_bit(i, fw_file->fw_features);
                                }
                        }
 
                        ath10k_dbg_dump(ar, ATH10K_DBG_BOOT, "features", "",
-                                       ar->fw_features,
-                                       sizeof(ar->fw_features));
+                                       ar->running_fw->fw_file.fw_features,
+                                       sizeof(fw_file->fw_features));
                        break;
                case ATH10K_FW_IE_FW_IMAGE:
                        ath10k_dbg(ar, ATH10K_DBG_BOOT,
                                   "found fw image ie (%zd B)\n",
                                   ie_len);
 
-                       ar->firmware_data = data;
-                       ar->firmware_len = ie_len;
+                       fw_file->firmware_data = data;
+                       fw_file->firmware_len = ie_len;
 
                        break;
                case ATH10K_FW_IE_OTP_IMAGE:
@@ -1161,8 +1095,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                                   "found otp image ie (%zd B)\n",
                                   ie_len);
 
-                       ar->otp_data = data;
-                       ar->otp_len = ie_len;
+                       fw_file->otp_data = data;
+                       fw_file->otp_len = ie_len;
 
                        break;
                case ATH10K_FW_IE_WMI_OP_VERSION:
@@ -1171,10 +1105,10 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
 
                        version = (__le32 *)data;
 
-                       ar->wmi.op_version = le32_to_cpup(version);
+                       fw_file->wmi_op_version = le32_to_cpup(version);
 
                        ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie wmi op version %d\n",
-                                  ar->wmi.op_version);
+                                  fw_file->wmi_op_version);
                        break;
                case ATH10K_FW_IE_HTT_OP_VERSION:
                        if (ie_len != sizeof(u32))
@@ -1182,17 +1116,17 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
 
                        version = (__le32 *)data;
 
-                       ar->htt.op_version = le32_to_cpup(version);
+                       fw_file->htt_op_version = le32_to_cpup(version);
 
                        ath10k_dbg(ar, ATH10K_DBG_BOOT, "found fw ie htt op version %d\n",
-                                  ar->htt.op_version);
+                                  fw_file->htt_op_version);
                        break;
                case ATH10K_FW_IE_FW_CODE_SWAP_IMAGE:
                        ath10k_dbg(ar, ATH10K_DBG_BOOT,
                                   "found fw code swap image ie (%zd B)\n",
                                   ie_len);
-                       ar->swap.firmware_codeswap_data = data;
-                       ar->swap.firmware_codeswap_len = ie_len;
+                       fw_file->codeswap_data = data;
+                       fw_file->codeswap_len = ie_len;
                        break;
                default:
                        ath10k_warn(ar, "Unknown FW IE: %u\n",
@@ -1207,7 +1141,8 @@ static int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name)
                data += ie_len;
        }
 
-       if (!ar->firmware_data || !ar->firmware_len) {
+       if (!fw_file->firmware_data ||
+           !fw_file->firmware_len) {
                ath10k_warn(ar, "No ATH10K_FW_IE_FW_IMAGE found from '%s/%s', skipping\n",
                            ar->hw_params.fw.dir, name);
                ret = -ENOMEDIUM;
@@ -1231,35 +1166,32 @@ static int ath10k_core_fetch_firmware_files(struct ath10k *ar)
        ar->fw_api = 5;
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
-       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API5_FILE);
+       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API5_FILE,
+                                              &ar->normal_mode_fw.fw_file);
        if (ret == 0)
                goto success;
 
        ar->fw_api = 4;
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
-       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE);
+       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API4_FILE,
+                                              &ar->normal_mode_fw.fw_file);
        if (ret == 0)
                goto success;
 
        ar->fw_api = 3;
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
-       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE);
+       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API3_FILE,
+                                              &ar->normal_mode_fw.fw_file);
        if (ret == 0)
                goto success;
 
        ar->fw_api = 2;
        ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
 
-       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE);
-       if (ret == 0)
-               goto success;
-
-       ar->fw_api = 1;
-       ath10k_dbg(ar, ATH10K_DBG_BOOT, "trying fw api %d\n", ar->fw_api);
-
-       ret = ath10k_core_fetch_firmware_api_1(ar);
+       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_API2_FILE,
+                                              &ar->normal_mode_fw.fw_file);
        if (ret)
                return ret;
 
@@ -1497,15 +1429,17 @@ static void ath10k_core_restart(struct work_struct *work)
 
 static int ath10k_core_init_firmware_features(struct ath10k *ar)
 {
-       if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, ar->fw_features) &&
-           !test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+       struct ath10k_fw_file *fw_file = &ar->normal_mode_fw.fw_file;
+
+       if (test_bit(ATH10K_FW_FEATURE_WMI_10_2, fw_file->fw_features) &&
+           !test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) {
                ath10k_err(ar, "feature bits corrupted: 10.2 feature requires 10.x feature to be set as well");
                return -EINVAL;
        }
 
-       if (ar->wmi.op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) {
+       if (fw_file->wmi_op_version >= ATH10K_FW_WMI_OP_VERSION_MAX) {
                ath10k_err(ar, "unsupported WMI OP version (max %d): %d\n",
-                          ATH10K_FW_WMI_OP_VERSION_MAX, ar->wmi.op_version);
+                          ATH10K_FW_WMI_OP_VERSION_MAX, fw_file->wmi_op_version);
                return -EINVAL;
        }
 
@@ -1517,7 +1451,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
                break;
        case ATH10K_CRYPT_MODE_SW:
                if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,
-                             ar->fw_features)) {
+                             fw_file->fw_features)) {
                        ath10k_err(ar, "cryptmode > 0 requires raw mode support from firmware");
                        return -EINVAL;
                }
@@ -1536,7 +1470,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
 
        if (rawmode) {
                if (!test_bit(ATH10K_FW_FEATURE_RAW_MODE_SUPPORT,
-                             ar->fw_features)) {
+                             fw_file->fw_features)) {
                        ath10k_err(ar, "rawmode = 1 requires support from firmware");
                        return -EINVAL;
                }
@@ -1561,19 +1495,19 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
        /* Backwards compatibility for firmwares without
         * ATH10K_FW_IE_WMI_OP_VERSION.
         */
-       if (ar->wmi.op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) {
-               if (test_bit(ATH10K_FW_FEATURE_WMI_10X, ar->fw_features)) {
+       if (fw_file->wmi_op_version == ATH10K_FW_WMI_OP_VERSION_UNSET) {
+               if (test_bit(ATH10K_FW_FEATURE_WMI_10X, fw_file->fw_features)) {
                        if (test_bit(ATH10K_FW_FEATURE_WMI_10_2,
-                                    ar->fw_features))
-                               ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_2;
+                                    fw_file->fw_features))
+                               fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_2;
                        else
-                               ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
+                               fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
                } else {
-                       ar->wmi.op_version = ATH10K_FW_WMI_OP_VERSION_MAIN;
+                       fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_MAIN;
                }
        }
 
-       switch (ar->wmi.op_version) {
+       switch (fw_file->wmi_op_version) {
        case ATH10K_FW_WMI_OP_VERSION_MAIN:
                ar->max_num_peers = TARGET_NUM_PEERS;
                ar->max_num_stations = TARGET_NUM_STATIONS;
@@ -1620,7 +1554,7 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
                ar->max_spatial_stream = ar->hw_params.max_spatial_stream;
 
                if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
-                            ar->fw_features))
+                            fw_file->fw_features))
                        ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC_PFC;
                else
                        ar->htt.max_num_pending_tx = TARGET_10_4_NUM_MSDU_DESC;
@@ -1634,18 +1568,18 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
        /* Backwards compatibility for firmwares without
         * ATH10K_FW_IE_HTT_OP_VERSION.
         */
-       if (ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_UNSET) {
-               switch (ar->wmi.op_version) {
+       if (fw_file->htt_op_version == ATH10K_FW_HTT_OP_VERSION_UNSET) {
+               switch (fw_file->wmi_op_version) {
                case ATH10K_FW_WMI_OP_VERSION_MAIN:
-                       ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_MAIN;
+                       fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_MAIN;
                        break;
                case ATH10K_FW_WMI_OP_VERSION_10_1:
                case ATH10K_FW_WMI_OP_VERSION_10_2:
                case ATH10K_FW_WMI_OP_VERSION_10_2_4:
-                       ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
+                       fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
                        break;
                case ATH10K_FW_WMI_OP_VERSION_TLV:
-                       ar->htt.op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
+                       fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_TLV;
                        break;
                case ATH10K_FW_WMI_OP_VERSION_10_4:
                case ATH10K_FW_WMI_OP_VERSION_UNSET:
@@ -1658,7 +1592,8 @@ static int ath10k_core_init_firmware_features(struct ath10k *ar)
        return 0;
 }
 
-int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
+int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
+                     const struct ath10k_fw_components *fw)
 {
        int status;
        u32 val;
@@ -1667,6 +1602,8 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
 
        clear_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags);
 
+       ar->running_fw = fw;
+
        ath10k_bmi_start(ar);
 
        if (ath10k_init_configure_target(ar)) {
@@ -1685,7 +1622,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
         * to set the clock source once the target is initialized.
         */
        if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_SKIP_CLOCK_INIT,
-                    ar->fw_features)) {
+                    ar->running_fw->fw_file.fw_features)) {
                status = ath10k_bmi_write32(ar, hi_skip_clock_init, 1);
                if (status) {
                        ath10k_err(ar, "could not write to skip_clock_init: %d\n",
@@ -1694,7 +1631,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
                }
        }
 
-       status = ath10k_download_fw(ar, mode);
+       status = ath10k_download_fw(ar);
        if (status)
                goto err;
 
@@ -1787,8 +1724,7 @@ int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode)
                if (ath10k_peer_stats_enabled(ar))
                        val = WMI_10_4_PEER_STATS;
 
-               status = ath10k_wmi_ext_resource_config(ar,
-                                                       WMI_HOST_PLATFORM_HIGH_PERF, val);
+               status = ath10k_mac_ext_resource_config(ar, val);
                if (status) {
                        ath10k_err(ar,
                                   "failed to send ext resource cfg command : %d\n",
@@ -1931,6 +1867,11 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
                goto err_power_down;
        }
 
+       BUILD_BUG_ON(sizeof(ar->hw->wiphy->fw_version) !=
+                    sizeof(ar->normal_mode_fw.fw_file.fw_version));
+       memcpy(ar->hw->wiphy->fw_version, ar->normal_mode_fw.fw_file.fw_version,
+              sizeof(ar->hw->wiphy->fw_version));
+
        ath10k_debug_print_hwfw_info(ar);
 
        ret = ath10k_core_pre_cal_download(ar);
@@ -1973,7 +1914,8 @@ static int ath10k_core_probe_fw(struct ath10k *ar)
 
        mutex_lock(&ar->conf_mutex);
 
-       ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
+       ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL,
+                               &ar->normal_mode_fw);
        if (ret) {
                ath10k_err(ar, "could not init core (%d)\n", ret);
                goto err_unlock;
index 362bbed..1379054 100644 (file)
@@ -44,8 +44,8 @@
 
 #define ATH10K_SCAN_ID 0
 #define WMI_READY_TIMEOUT (5 * HZ)
-#define ATH10K_FLUSH_TIMEOUT_HZ (5*HZ)
-#define ATH10K_CONNECTION_LOSS_HZ (3*HZ)
+#define ATH10K_FLUSH_TIMEOUT_HZ (5 * HZ)
+#define ATH10K_CONNECTION_LOSS_HZ (3 * HZ)
 #define ATH10K_NUM_CHANS 39
 
 /* Antenna noise floor */
@@ -139,7 +139,6 @@ struct ath10k_mem_chunk {
 };
 
 struct ath10k_wmi {
-       enum ath10k_fw_wmi_op_version op_version;
        enum ath10k_htc_ep_id eid;
        struct completion service_ready;
        struct completion unified_ready;
@@ -334,7 +333,7 @@ struct ath10k_sta {
 #endif
 };
 
-#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5*HZ)
+#define ATH10K_VDEV_SETUP_TIMEOUT_HZ (5 * HZ)
 
 enum ath10k_beacon_state {
        ATH10K_BEACON_SCHEDULED = 0,
@@ -627,6 +626,34 @@ enum ath10k_tx_pause_reason {
        ATH10K_TX_PAUSE_MAX,
 };
 
+struct ath10k_fw_file {
+       const struct firmware *firmware;
+
+       char fw_version[ETHTOOL_FWVERS_LEN];
+
+       DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
+
+       enum ath10k_fw_wmi_op_version wmi_op_version;
+       enum ath10k_fw_htt_op_version htt_op_version;
+
+       const void *firmware_data;
+       size_t firmware_len;
+
+       const void *otp_data;
+       size_t otp_len;
+
+       const void *codeswap_data;
+       size_t codeswap_len;
+};
+
+struct ath10k_fw_components {
+       const struct firmware *board;
+       const void *board_data;
+       size_t board_len;
+
+       struct ath10k_fw_file fw_file;
+};
+
 struct ath10k {
        struct ath_common ath_common;
        struct ieee80211_hw *hw;
@@ -652,8 +679,6 @@ struct ath10k {
        /* protected by conf_mutex */
        bool ani_enabled;
 
-       DECLARE_BITMAP(fw_features, ATH10K_FW_FEATURE_COUNT);
-
        bool p2p;
 
        struct {
@@ -708,32 +733,24 @@ struct ath10k {
 
                struct ath10k_hw_params_fw {
                        const char *dir;
-                       const char *fw;
-                       const char *otp;
                        const char *board;
                        size_t board_size;
                        size_t board_ext_size;
                } fw;
        } hw_params;
 
-       const struct firmware *board;
-       const void *board_data;
-       size_t board_len;
-
-       const struct firmware *otp;
-       const void *otp_data;
-       size_t otp_len;
+       /* contains the firmware images used with ATH10K_FIRMWARE_MODE_NORMAL */
+       struct ath10k_fw_components normal_mode_fw;
 
-       const struct firmware *firmware;
-       const void *firmware_data;
-       size_t firmware_len;
+       /* READ-ONLY images of the running firmware, which can be either
+        * normal or UTF. Do not modify, release etc!
+        */
+       const struct ath10k_fw_components *running_fw;
 
        const struct firmware *pre_cal_file;
        const struct firmware *cal_file;
 
        struct {
-               const void *firmware_codeswap_data;
-               size_t firmware_codeswap_len;
                struct ath10k_swap_code_seg_info *firmware_swap_code_seg_info;
        } swap;
 
@@ -879,13 +896,8 @@ struct ath10k {
 
        struct {
                /* protected by conf_mutex */
-               const struct firmware *utf;
-               char utf_version[32];
-               const void *utf_firmware_data;
-               size_t utf_firmware_len;
-               DECLARE_BITMAP(orig_fw_features, ATH10K_FW_FEATURE_COUNT);
-               enum ath10k_fw_wmi_op_version orig_wmi_op_version;
-               enum ath10k_fw_wmi_op_version op_version;
+               struct ath10k_fw_components utf_mode_fw;
+
                /* protected by data_lock */
                bool utf_monitor;
        } testmode;
@@ -921,8 +933,11 @@ void ath10k_core_destroy(struct ath10k *ar);
 void ath10k_core_get_fw_features_str(struct ath10k *ar,
                                     char *buf,
                                     size_t max_len);
+int ath10k_core_fetch_firmware_api_n(struct ath10k *ar, const char *name,
+                                    struct ath10k_fw_file *fw_file);
 
-int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode);
+int ath10k_core_start(struct ath10k *ar, enum ath10k_firmware_mode mode,
+                     const struct ath10k_fw_components *fw_components);
 int ath10k_wait_for_suspend(struct ath10k *ar, u32 suspend_opt);
 void ath10k_core_stop(struct ath10k *ar);
 int ath10k_core_register(struct ath10k *ar, u32 chip_id);
index 76bbe17..e251155 100644 (file)
@@ -126,6 +126,7 @@ EXPORT_SYMBOL(ath10k_info);
 
 void ath10k_debug_print_hwfw_info(struct ath10k *ar)
 {
+       const struct firmware *firmware;
        char fw_features[128] = {};
        u32 crc = 0;
 
@@ -144,8 +145,9 @@ void ath10k_debug_print_hwfw_info(struct ath10k *ar)
                    config_enabled(CONFIG_ATH10K_DFS_CERTIFIED),
                    config_enabled(CONFIG_NL80211_TESTMODE));
 
-       if (ar->firmware)
-               crc = crc32_le(0, ar->firmware->data, ar->firmware->size);
+       firmware = ar->normal_mode_fw.fw_file.firmware;
+       if (firmware)
+               crc = crc32_le(0, firmware->data, firmware->size);
 
        ath10k_info(ar, "firmware ver %s api %d features %s crc32 %08x\n",
                    ar->hw->wiphy->fw_version,
@@ -167,7 +169,8 @@ void ath10k_debug_print_board_info(struct ath10k *ar)
        ath10k_info(ar, "board_file api %d bmi_id %s crc32 %08x",
                    ar->bd_api,
                    boardinfo,
-                   crc32_le(0, ar->board->data, ar->board->size));
+                   crc32_le(0, ar->normal_mode_fw.board->data,
+                            ar->normal_mode_fw.board->size));
 }
 
 void ath10k_debug_print_boot_info(struct ath10k *ar)
@@ -175,8 +178,8 @@ void ath10k_debug_print_boot_info(struct ath10k *ar)
        ath10k_info(ar, "htt-ver %d.%d wmi-op %d htt-op %d cal %s max-sta %d raw %d hwcrypto %d\n",
                    ar->htt.target_version_major,
                    ar->htt.target_version_minor,
-                   ar->wmi.op_version,
-                   ar->htt.op_version,
+                   ar->normal_mode_fw.fw_file.wmi_op_version,
+                   ar->normal_mode_fw.fw_file.htt_op_version,
                    ath10k_cal_mode_str(ar->cal_mode),
                    ar->max_num_stations,
                    test_bit(ATH10K_FLAG_RAW_MODE, &ar->dev_flags),
@@ -2122,7 +2125,7 @@ static ssize_t ath10k_write_btcoex(struct file *file,
        struct ath10k *ar = file->private_data;
        char buf[32];
        size_t buf_size;
-       int ret = 0;
+       int ret;
        bool val;
 
        buf_size = min(count, (sizeof(buf) - 1));
@@ -2142,8 +2145,10 @@ static ssize_t ath10k_write_btcoex(struct file *file,
                goto exit;
        }
 
-       if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val))
+       if (!(test_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags) ^ val)) {
+               ret = count;
                goto exit;
+       }
 
        if (val)
                set_bit(ATH10K_FLAG_BTCOEX, &ar->dev_flags);
@@ -2189,7 +2194,7 @@ static ssize_t ath10k_write_peer_stats(struct file *file,
        struct ath10k *ar = file->private_data;
        char buf[32];
        size_t buf_size;
-       int ret = 0;
+       int ret;
        bool val;
 
        buf_size = min(count, (sizeof(buf) - 1));
@@ -2209,8 +2214,10 @@ static ssize_t ath10k_write_peer_stats(struct file *file,
                goto exit;
        }
 
-       if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val))
+       if (!(test_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags) ^ val)) {
+               ret = count;
                goto exit;
+       }
 
        if (val)
                set_bit(ATH10K_FLAG_PEER_STATS, &ar->dev_flags);
@@ -2266,23 +2273,28 @@ static ssize_t ath10k_debug_fw_checksums_read(struct file *file,
 
        len += scnprintf(buf + len, buf_len - len,
                         "firmware-N.bin\t\t%08x\n",
-                        crc32_le(0, ar->firmware->data, ar->firmware->size));
+                        crc32_le(0, ar->normal_mode_fw.fw_file.firmware->data,
+                                 ar->normal_mode_fw.fw_file.firmware->size));
        len += scnprintf(buf + len, buf_len - len,
                         "athwlan\t\t\t%08x\n",
-                        crc32_le(0, ar->firmware_data, ar->firmware_len));
+                        crc32_le(0, ar->normal_mode_fw.fw_file.firmware_data,
+                                 ar->normal_mode_fw.fw_file.firmware_len));
        len += scnprintf(buf + len, buf_len - len,
                         "otp\t\t\t%08x\n",
-                        crc32_le(0, ar->otp_data, ar->otp_len));
+                        crc32_le(0, ar->normal_mode_fw.fw_file.otp_data,
+                                 ar->normal_mode_fw.fw_file.otp_len));
        len += scnprintf(buf + len, buf_len - len,
                         "codeswap\t\t%08x\n",
-                        crc32_le(0, ar->swap.firmware_codeswap_data,
-                                 ar->swap.firmware_codeswap_len));
+                        crc32_le(0, ar->normal_mode_fw.fw_file.codeswap_data,
+                                 ar->normal_mode_fw.fw_file.codeswap_len));
        len += scnprintf(buf + len, buf_len - len,
                         "board-N.bin\t\t%08x\n",
-                        crc32_le(0, ar->board->data, ar->board->size));
+                        crc32_le(0, ar->normal_mode_fw.board->data,
+                                 ar->normal_mode_fw.board->size));
        len += scnprintf(buf + len, buf_len - len,
                         "board\t\t\t%08x\n",
-                        crc32_le(0, ar->board_data, ar->board_len));
+                        crc32_le(0, ar->normal_mode_fw.board_data,
+                                 ar->normal_mode_fw.board_len));
 
        ret_cnt = simple_read_from_buffer(user_buf, count, ppos, buf, len);
 
index 6206edd..75c89e3 100644 (file)
@@ -57,7 +57,7 @@ enum ath10k_dbg_aggr_mode {
 };
 
 /* FIXME: How to calculate the buffer size sanely? */
-#define ATH10K_FW_STATS_BUF_SIZE (1024*1024)
+#define ATH10K_FW_STATS_BUF_SIZE (1024 * 1024)
 
 extern unsigned int ath10k_debug_mask;
 
index e70aa38..cc82718 100644 (file)
@@ -297,10 +297,10 @@ struct ath10k_htc_svc_conn_resp {
 #define ATH10K_NUM_CONTROL_TX_BUFFERS 2
 #define ATH10K_HTC_MAX_LEN 4096
 #define ATH10K_HTC_MAX_CTRL_MSG_LEN 256
-#define ATH10K_HTC_WAIT_TIMEOUT_HZ (1*HZ)
+#define ATH10K_HTC_WAIT_TIMEOUT_HZ (1 * HZ)
 #define ATH10K_HTC_CONTROL_BUFFER_SIZE (ATH10K_HTC_MAX_CTRL_MSG_LEN + \
                                        sizeof(struct ath10k_htc_hdr))
-#define ATH10K_HTC_CONN_SVC_TIMEOUT_HZ (1*HZ)
+#define ATH10K_HTC_CONN_SVC_TIMEOUT_HZ (1 * HZ)
 
 struct ath10k_htc_ep {
        struct ath10k_htc *htc;
index 17a3008..130cd95 100644 (file)
@@ -183,7 +183,7 @@ int ath10k_htt_init(struct ath10k *ar)
                8 + /* llc snap */
                2; /* ip4 dscp or ip6 priority */
 
-       switch (ar->htt.op_version) {
+       switch (ar->running_fw->fw_file.htt_op_version) {
        case ATH10K_FW_HTT_OP_VERSION_10_4:
                ar->htt.t2h_msg_types = htt_10_4_t2h_msg_types;
                ar->htt.t2h_msg_types_max = HTT_10_4_T2H_NUM_MSGS;
@@ -208,7 +208,7 @@ int ath10k_htt_init(struct ath10k *ar)
        return 0;
 }
 
-#define HTT_TARGET_VERSION_TIMEOUT_HZ (3*HZ)
+#define HTT_TARGET_VERSION_TIMEOUT_HZ (3 * HZ)
 
 static int ath10k_htt_verify_version(struct ath10k_htt *htt)
 {
index 60bd9fe..911c535 100644 (file)
@@ -1475,10 +1475,10 @@ union htt_rx_pn_t {
        u32 pn24;
 
        /* TKIP or CCMP: 48-bit PN */
-       u_int64_t pn48;
+       u64 pn48;
 
        /* WAPI: 128-bit PN */
-       u_int64_t pn128[2];
+       u64 pn128[2];
 };
 
 struct htt_cmd {
@@ -1562,7 +1562,6 @@ struct ath10k_htt {
        u8 target_version_major;
        u8 target_version_minor;
        struct completion target_version_received;
-       enum ath10k_fw_htt_op_version op_version;
        u8 max_num_amsdu;
        u8 max_num_ampdu;
 
index 079fef5..cc979a4 100644 (file)
@@ -966,7 +966,7 @@ static int ath10k_htt_rx_nwifi_hdrlen(struct ath10k *ar,
        int len = ieee80211_hdrlen(hdr->frame_control);
 
        if (!test_bit(ATH10K_FW_FEATURE_NO_NWIFI_DECAP_4ADDR_PADDING,
-                     ar->fw_features))
+                     ar->running_fw->fw_file.fw_features))
                len = round_up(len, 4);
 
        return len;
index 9baa2e6..6269c61 100644 (file)
@@ -267,7 +267,8 @@ static void ath10k_htt_tx_free_txq(struct ath10k_htt *htt)
        struct ath10k *ar = htt->ar;
        size_t size;
 
-       if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
+       if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
+                     ar->running_fw->fw_file.fw_features))
                return;
 
        size = sizeof(*htt->tx_q_state.vaddr);
@@ -282,7 +283,8 @@ static int ath10k_htt_tx_alloc_txq(struct ath10k_htt *htt)
        size_t size;
        int ret;
 
-       if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
+       if (!test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
+                     ar->running_fw->fw_file.fw_features))
                return 0;
 
        htt->tx_q_state.num_peers = HTT_TX_Q_STATE_NUM_PEERS;
@@ -513,7 +515,8 @@ int ath10k_htt_send_frag_desc_bank_cfg(struct ath10k_htt *htt)
        info |= SM(htt->tx_q_state.type,
                   HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_DEPTH_TYPE);
 
-       if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL, ar->fw_features))
+       if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
+                    ar->running_fw->fw_file.fw_features))
                info |= HTT_FRAG_DESC_BANK_CFG_INFO_Q_STATE_VALID;
 
        cfg = &cmd->frag_desc_bank_cfg;
index c0179bc..aedd898 100644 (file)
@@ -35,8 +35,6 @@
 #define QCA988X_HW_2_0_VERSION         0x4100016c
 #define QCA988X_HW_2_0_CHIP_ID_REV     0x2
 #define QCA988X_HW_2_0_FW_DIR          ATH10K_FW_DIR "/QCA988X/hw2.0"
-#define QCA988X_HW_2_0_FW_FILE         "firmware.bin"
-#define QCA988X_HW_2_0_OTP_FILE                "otp.bin"
 #define QCA988X_HW_2_0_BOARD_DATA_FILE "board.bin"
 #define QCA988X_HW_2_0_PATCH_LOAD_ADDR 0x1234
 
@@ -76,14 +74,10 @@ enum qca9377_chip_id_rev {
 };
 
 #define QCA6174_HW_2_1_FW_DIR          "ath10k/QCA6174/hw2.1"
-#define QCA6174_HW_2_1_FW_FILE         "firmware.bin"
-#define QCA6174_HW_2_1_OTP_FILE                "otp.bin"
 #define QCA6174_HW_2_1_BOARD_DATA_FILE "board.bin"
 #define QCA6174_HW_2_1_PATCH_LOAD_ADDR 0x1234
 
 #define QCA6174_HW_3_0_FW_DIR          "ath10k/QCA6174/hw3.0"
-#define QCA6174_HW_3_0_FW_FILE         "firmware.bin"
-#define QCA6174_HW_3_0_OTP_FILE                "otp.bin"
 #define QCA6174_HW_3_0_BOARD_DATA_FILE "board.bin"
 #define QCA6174_HW_3_0_PATCH_LOAD_ADDR 0x1234
 
@@ -94,23 +88,17 @@ enum qca9377_chip_id_rev {
 #define QCA99X0_HW_2_0_DEV_VERSION     0x01000000
 #define QCA99X0_HW_2_0_CHIP_ID_REV     0x1
 #define QCA99X0_HW_2_0_FW_DIR          ATH10K_FW_DIR "/QCA99X0/hw2.0"
-#define QCA99X0_HW_2_0_FW_FILE         "firmware.bin"
-#define QCA99X0_HW_2_0_OTP_FILE        "otp.bin"
 #define QCA99X0_HW_2_0_BOARD_DATA_FILE "board.bin"
 #define QCA99X0_HW_2_0_PATCH_LOAD_ADDR 0x1234
 
 /* QCA9377 1.0 definitions */
 #define QCA9377_HW_1_0_FW_DIR          ATH10K_FW_DIR "/QCA9377/hw1.0"
-#define QCA9377_HW_1_0_FW_FILE         "firmware.bin"
-#define QCA9377_HW_1_0_OTP_FILE        "otp.bin"
 #define QCA9377_HW_1_0_BOARD_DATA_FILE "board.bin"
 #define QCA9377_HW_1_0_PATCH_LOAD_ADDR 0x1234
 
 /* QCA4019 1.0 definitions */
 #define QCA4019_HW_1_0_DEV_VERSION     0x01000000
 #define QCA4019_HW_1_0_FW_DIR          ATH10K_FW_DIR "/QCA4019/hw1.0"
-#define QCA4019_HW_1_0_FW_FILE         "firmware.bin"
-#define QCA4019_HW_1_0_OTP_FILE        "otp.bin"
 #define QCA4019_HW_1_0_BOARD_DATA_FILE "board.bin"
 #define QCA4019_HW_1_0_PATCH_LOAD_ADDR  0x1234
 
index 6ace10b..0e24f9e 100644 (file)
@@ -157,6 +157,26 @@ ath10k_mac_max_vht_nss(const u16 vht_mcs_mask[NL80211_VHT_NSS_MAX])
        return 1;
 }
 
+int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val)
+{
+       enum wmi_host_platform_type platform_type;
+       int ret;
+
+       if (test_bit(WMI_SERVICE_TX_MODE_DYNAMIC, ar->wmi.svc_map))
+               platform_type = WMI_HOST_PLATFORM_LOW_PERF;
+       else
+               platform_type = WMI_HOST_PLATFORM_HIGH_PERF;
+
+       ret = ath10k_wmi_ext_resource_config(ar, platform_type, val);
+
+       if (ret && ret != -EOPNOTSUPP) {
+               ath10k_warn(ar, "failed to configure ext resource: %d\n", ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 /**********/
 /* Crypto */
 /**********/
@@ -449,10 +469,10 @@ static int ath10k_mac_vif_update_wep_key(struct ath10k_vif *arvif,
        lockdep_assert_held(&ar->conf_mutex);
 
        list_for_each_entry(peer, &ar->peers, list) {
-               if (!memcmp(peer->addr, arvif->vif->addr, ETH_ALEN))
+               if (ether_addr_equal(peer->addr, arvif->vif->addr))
                        continue;
 
-               if (!memcmp(peer->addr, arvif->bssid, ETH_ALEN))
+               if (ether_addr_equal(peer->addr, arvif->bssid))
                        continue;
 
                if (peer->keys[key->keyidx] == key)
@@ -1752,7 +1772,7 @@ static int ath10k_mac_vif_setup_ps(struct ath10k_vif *arvif)
 
        if (enable_ps && ath10k_mac_num_vifs_started(ar) > 1 &&
            !test_bit(ATH10K_FW_FEATURE_MULTI_VIF_PS_SUPPORT,
-                     ar->fw_features)) {
+                     ar->running_fw->fw_file.fw_features)) {
                ath10k_warn(ar, "refusing to enable ps on vdev %i: not supported by fw\n",
                            arvif->vdev_id);
                enable_ps = false;
@@ -2040,7 +2060,8 @@ static void ath10k_peer_assoc_h_crypto(struct ath10k *ar,
        }
 
        if (sta->mfp &&
-           test_bit(ATH10K_FW_FEATURE_MFP_SUPPORT, ar->fw_features)) {
+           test_bit(ATH10K_FW_FEATURE_MFP_SUPPORT,
+                    ar->running_fw->fw_file.fw_features)) {
                arg->peer_flags |= ar->wmi.peer_flags->pmf;
        }
 }
@@ -3187,7 +3208,8 @@ ath10k_mac_tx_h_get_txmode(struct ath10k *ar,
         */
        if (ar->htt.target_version_major < 3 &&
            (ieee80211_is_nullfunc(fc) || ieee80211_is_qos_nullfunc(fc)) &&
-           !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX, ar->fw_features))
+           !test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
+                     ar->running_fw->fw_file.fw_features))
                return ATH10K_HW_TXRX_MGMT;
 
        /* Workaround:
@@ -3337,7 +3359,7 @@ bool ath10k_mac_tx_frm_has_freq(struct ath10k *ar)
         */
        return (ar->htt.target_version_major >= 3 &&
                ar->htt.target_version_minor >= 4 &&
-               ar->htt.op_version == ATH10K_FW_HTT_OP_VERSION_TLV);
+               ar->running_fw->fw_file.htt_op_version == ATH10K_FW_HTT_OP_VERSION_TLV);
 }
 
 static int ath10k_mac_tx_wmi_mgmt(struct ath10k *ar, struct sk_buff *skb)
@@ -3374,7 +3396,7 @@ ath10k_mac_tx_h_get_txpath(struct ath10k *ar,
                return ATH10K_MAC_TX_HTT;
        case ATH10K_HW_TXRX_MGMT:
                if (test_bit(ATH10K_FW_FEATURE_HAS_WMI_MGMT_TX,
-                            ar->fw_features))
+                            ar->running_fw->fw_file.fw_features))
                        return ATH10K_MAC_TX_WMI_MGMT;
                else if (ar->htt.target_version_major >= 3)
                        return ATH10K_MAC_TX_HTT;
@@ -3846,7 +3868,7 @@ static int ath10k_scan_stop(struct ath10k *ar)
                goto out;
        }
 
-       ret = wait_for_completion_timeout(&ar->scan.completed, 3*HZ);
+       ret = wait_for_completion_timeout(&ar->scan.completed, 3 * HZ);
        if (ret == 0) {
                ath10k_warn(ar, "failed to receive scan abortion completion: timed out\n");
                ret = -ETIMEDOUT;
@@ -3926,7 +3948,7 @@ static int ath10k_start_scan(struct ath10k *ar,
        if (ret)
                return ret;
 
-       ret = wait_for_completion_timeout(&ar->scan.started, 1*HZ);
+       ret = wait_for_completion_timeout(&ar->scan.started, 1 * HZ);
        if (ret == 0) {
                ret = ath10k_scan_stop(ar);
                if (ret)
@@ -4356,7 +4378,8 @@ static int ath10k_start(struct ieee80211_hw *hw)
                goto err_off;
        }
 
-       ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL);
+       ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_NORMAL,
+                               &ar->normal_mode_fw);
        if (ret) {
                ath10k_err(ar, "Could not init core: %d\n", ret);
                goto err_power_down;
@@ -4414,7 +4437,7 @@ static int ath10k_start(struct ieee80211_hw *hw)
        }
 
        if (test_bit(ATH10K_FW_FEATURE_SUPPORTS_ADAPTIVE_CCA,
-                    ar->fw_features)) {
+                    ar->running_fw->fw_file.fw_features)) {
                ret = ath10k_wmi_pdev_enable_adaptive_cca(ar, 1,
                                                          WMI_CCA_DETECT_LEVEL_AUTO,
                                                          WMI_CCA_DETECT_MARGIN_AUTO);
@@ -6168,7 +6191,7 @@ exit:
        return ret;
 }
 
-#define ATH10K_ROC_TIMEOUT_HZ (2*HZ)
+#define ATH10K_ROC_TIMEOUT_HZ (2 * HZ)
 
 static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
                                    struct ieee80211_vif *vif,
@@ -6232,7 +6255,7 @@ static int ath10k_remain_on_channel(struct ieee80211_hw *hw,
                goto exit;
        }
 
-       ret = wait_for_completion_timeout(&ar->scan.on_channel, 3*HZ);
+       ret = wait_for_completion_timeout(&ar->scan.on_channel, 3 * HZ);
        if (ret == 0) {
                ath10k_warn(ar, "failed to switch to channel for roc scan\n");
 
@@ -6796,6 +6819,32 @@ static u64 ath10k_get_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
        return 0;
 }
 
+static void ath10k_set_tsf(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
+                          u64 tsf)
+{
+       struct ath10k *ar = hw->priv;
+       struct ath10k_vif *arvif = ath10k_vif_to_arvif(vif);
+       u32 tsf_offset, vdev_param = ar->wmi.vdev_param->set_tsf;
+       int ret;
+
+       /* Workaround:
+        *
+        * Given tsf argument is entire TSF value, but firmware accepts
+        * only TSF offset to current TSF.
+        *
+        * get_tsf function is used to get offset value, however since
+        * ath10k_get_tsf is not implemented properly, it will return 0 always.
+        * Luckily all the caller functions to set_tsf, as of now, also rely on
+        * get_tsf function to get entire tsf value such get_tsf() + tsf_delta,
+        * final tsf offset value to firmware will be arithmetically correct.
+        */
+       tsf_offset = tsf - ath10k_get_tsf(hw, vif);
+       ret = ath10k_wmi_vdev_set_param(ar, arvif->vdev_id,
+                                       vdev_param, tsf_offset);
+       if (ret && ret != -EOPNOTSUPP)
+               ath10k_warn(ar, "failed to set tsf offset: %d\n", ret);
+}
+
 static int ath10k_ampdu_action(struct ieee80211_hw *hw,
                               struct ieee80211_vif *vif,
                               struct ieee80211_ampdu_params *params)
@@ -6867,7 +6916,13 @@ ath10k_mac_update_rx_channel(struct ath10k *ar,
                        def = &vifs[0].new_ctx->def;
 
                ar->rx_channel = def->chan;
-       } else if (ctx && ath10k_mac_num_chanctxs(ar) == 0) {
+       } else if ((ctx && ath10k_mac_num_chanctxs(ar) == 0) ||
+                  (ctx && (ar->state == ATH10K_STATE_RESTARTED))) {
+               /* During driver restart due to firmware assert, since mac80211
+                * already has valid channel context for given radio, channel
+                * context iteration return num_chanctx > 0. So fix rx_channel
+                * when restart is in progress.
+                */
                ar->rx_channel = ctx->def.chan;
        } else {
                ar->rx_channel = NULL;
@@ -7252,6 +7307,7 @@ static const struct ieee80211_ops ath10k_ops = {
        .set_bitrate_mask               = ath10k_mac_op_set_bitrate_mask,
        .sta_rc_update                  = ath10k_sta_rc_update,
        .get_tsf                        = ath10k_get_tsf,
+       .set_tsf                        = ath10k_set_tsf,
        .ampdu_action                   = ath10k_ampdu_action,
        .get_et_sset_count              = ath10k_debug_get_et_sset_count,
        .get_et_stats                   = ath10k_debug_get_et_stats,
@@ -7640,7 +7696,7 @@ int ath10k_mac_register(struct ath10k *ar)
        ar->hw->wiphy->available_antennas_rx = ar->cfg_rx_chainmask;
        ar->hw->wiphy->available_antennas_tx = ar->cfg_tx_chainmask;
 
-       if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->fw_features))
+       if (!test_bit(ATH10K_FW_FEATURE_NO_P2P, ar->normal_mode_fw.fw_file.fw_features))
                ar->hw->wiphy->interface_modes |=
                        BIT(NL80211_IFTYPE_P2P_DEVICE) |
                        BIT(NL80211_IFTYPE_P2P_CLIENT) |
@@ -7730,7 +7786,7 @@ int ath10k_mac_register(struct ath10k *ar)
         */
        ar->hw->offchannel_tx_hw_queue = IEEE80211_MAX_QUEUES - 1;
 
-       switch (ar->wmi.op_version) {
+       switch (ar->running_fw->fw_file.wmi_op_version) {
        case ATH10K_FW_WMI_OP_VERSION_MAIN:
                ar->hw->wiphy->iface_combinations = ath10k_if_comb;
                ar->hw->wiphy->n_iface_combinations =
index 2c3327b..1bd29ec 100644 (file)
@@ -81,6 +81,7 @@ int ath10k_mac_tx_push_txq(struct ieee80211_hw *hw,
 struct ieee80211_txq *ath10k_mac_txq_lookup(struct ath10k *ar,
                                            u16 peer_id,
                                            u8 tid);
+int ath10k_mac_ext_resource_config(struct ath10k *ar, u32 val);
 
 static inline struct ath10k_vif *ath10k_vif_to_arvif(struct ieee80211_vif *vif)
 {
index 0b305ef..8133d7b 100644 (file)
 #include "ce.h"
 #include "pci.h"
 
-enum ath10k_pci_irq_mode {
-       ATH10K_PCI_IRQ_AUTO = 0,
-       ATH10K_PCI_IRQ_LEGACY = 1,
-       ATH10K_PCI_IRQ_MSI = 2,
-};
-
 enum ath10k_pci_reset_mode {
        ATH10K_PCI_RESET_AUTO = 0,
        ATH10K_PCI_RESET_WARM_ONLY = 1,
@@ -745,10 +739,7 @@ static inline const char *ath10k_pci_get_irq_method(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       if (ar_pci->num_msi_intrs > 1)
-               return "msi-x";
-
-       if (ar_pci->num_msi_intrs == 1)
+       if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_MSI)
                return "msi";
 
        return "legacy";
@@ -1502,13 +1493,8 @@ void ath10k_pci_hif_send_complete_check(struct ath10k *ar, u8 pipe,
 void ath10k_pci_kill_tasklet(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int i;
 
        tasklet_kill(&ar_pci->intr_tq);
-       tasklet_kill(&ar_pci->msi_fw_err);
-
-       for (i = 0; i < CE_COUNT; i++)
-               tasklet_kill(&ar_pci->pipe_info[i].intr);
 
        del_timer_sync(&ar_pci->rx_post_retry);
 }
@@ -1624,10 +1610,8 @@ static void ath10k_pci_irq_disable(struct ath10k *ar)
 static void ath10k_pci_irq_sync(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int i;
 
-       for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
-               synchronize_irq(ar_pci->pdev->irq + i);
+       synchronize_irq(ar_pci->pdev->irq);
 }
 
 static void ath10k_pci_irq_enable(struct ath10k *ar)
@@ -2596,65 +2580,6 @@ static const struct ath10k_hif_ops ath10k_pci_hif_ops = {
 #endif
 };
 
-static void ath10k_pci_ce_tasklet(unsigned long ptr)
-{
-       struct ath10k_pci_pipe *pipe = (struct ath10k_pci_pipe *)ptr;
-       struct ath10k_pci *ar_pci = pipe->ar_pci;
-
-       ath10k_ce_per_engine_service(ar_pci->ar, pipe->pipe_num);
-}
-
-static void ath10k_msi_err_tasklet(unsigned long data)
-{
-       struct ath10k *ar = (struct ath10k *)data;
-
-       if (!ath10k_pci_has_fw_crashed(ar)) {
-               ath10k_warn(ar, "received unsolicited fw crash interrupt\n");
-               return;
-       }
-
-       ath10k_pci_irq_disable(ar);
-       ath10k_pci_fw_crashed_clear(ar);
-       ath10k_pci_fw_crashed_dump(ar);
-}
-
-/*
- * Handler for a per-engine interrupt on a PARTICULAR CE.
- * This is used in cases where each CE has a private MSI interrupt.
- */
-static irqreturn_t ath10k_pci_per_engine_handler(int irq, void *arg)
-{
-       struct ath10k *ar = arg;
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int ce_id = irq - ar_pci->pdev->irq - MSI_ASSIGN_CE_INITIAL;
-
-       if (ce_id < 0 || ce_id >= ARRAY_SIZE(ar_pci->pipe_info)) {
-               ath10k_warn(ar, "unexpected/invalid irq %d ce_id %d\n", irq,
-                           ce_id);
-               return IRQ_HANDLED;
-       }
-
-       /*
-        * NOTE: We are able to derive ce_id from irq because we
-        * use a one-to-one mapping for CE's 0..5.
-        * CE's 6 & 7 do not use interrupts at all.
-        *
-        * This mapping must be kept in sync with the mapping
-        * used by firmware.
-        */
-       tasklet_schedule(&ar_pci->pipe_info[ce_id].intr);
-       return IRQ_HANDLED;
-}
-
-static irqreturn_t ath10k_pci_msi_fw_handler(int irq, void *arg)
-{
-       struct ath10k *ar = arg;
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-
-       tasklet_schedule(&ar_pci->msi_fw_err);
-       return IRQ_HANDLED;
-}
-
 /*
  * Top-level interrupt handler for all PCI interrupts from a Target.
  * When a block of MSI interrupts is allocated, this top-level handler
@@ -2672,7 +2597,7 @@ static irqreturn_t ath10k_pci_interrupt_handler(int irq, void *arg)
                return IRQ_NONE;
        }
 
-       if (ar_pci->num_msi_intrs == 0) {
+       if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY) {
                if (!ath10k_pci_irq_pending(ar))
                        return IRQ_NONE;
 
@@ -2699,43 +2624,10 @@ static void ath10k_pci_tasklet(unsigned long data)
        ath10k_ce_per_engine_service_any(ar);
 
        /* Re-enable legacy irq that was disabled in the irq handler */
-       if (ar_pci->num_msi_intrs == 0)
+       if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY)
                ath10k_pci_enable_legacy_irq(ar);
 }
 
-static int ath10k_pci_request_irq_msix(struct ath10k *ar)
-{
-       struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int ret, i;
-
-       ret = request_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW,
-                         ath10k_pci_msi_fw_handler,
-                         IRQF_SHARED, "ath10k_pci", ar);
-       if (ret) {
-               ath10k_warn(ar, "failed to request MSI-X fw irq %d: %d\n",
-                           ar_pci->pdev->irq + MSI_ASSIGN_FW, ret);
-               return ret;
-       }
-
-       for (i = MSI_ASSIGN_CE_INITIAL; i <= MSI_ASSIGN_CE_MAX; i++) {
-               ret = request_irq(ar_pci->pdev->irq + i,
-                                 ath10k_pci_per_engine_handler,
-                                 IRQF_SHARED, "ath10k_pci", ar);
-               if (ret) {
-                       ath10k_warn(ar, "failed to request MSI-X ce irq %d: %d\n",
-                                   ar_pci->pdev->irq + i, ret);
-
-                       for (i--; i >= MSI_ASSIGN_CE_INITIAL; i--)
-                               free_irq(ar_pci->pdev->irq + i, ar);
-
-                       free_irq(ar_pci->pdev->irq + MSI_ASSIGN_FW, ar);
-                       return ret;
-               }
-       }
-
-       return 0;
-}
-
 static int ath10k_pci_request_irq_msi(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
@@ -2774,41 +2666,28 @@ static int ath10k_pci_request_irq(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       switch (ar_pci->num_msi_intrs) {
-       case 0:
+       switch (ar_pci->oper_irq_mode) {
+       case ATH10K_PCI_IRQ_LEGACY:
                return ath10k_pci_request_irq_legacy(ar);
-       case 1:
+       case ATH10K_PCI_IRQ_MSI:
                return ath10k_pci_request_irq_msi(ar);
        default:
-               return ath10k_pci_request_irq_msix(ar);
+               return -EINVAL;
        }
 }
 
 static void ath10k_pci_free_irq(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int i;
 
-       /* There's at least one interrupt irregardless whether its legacy INTR
-        * or MSI or MSI-X */
-       for (i = 0; i < max(1, ar_pci->num_msi_intrs); i++)
-               free_irq(ar_pci->pdev->irq + i, ar);
+       free_irq(ar_pci->pdev->irq, ar);
 }
 
 void ath10k_pci_init_irq_tasklets(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
-       int i;
 
        tasklet_init(&ar_pci->intr_tq, ath10k_pci_tasklet, (unsigned long)ar);
-       tasklet_init(&ar_pci->msi_fw_err, ath10k_msi_err_tasklet,
-                    (unsigned long)ar);
-
-       for (i = 0; i < CE_COUNT; i++) {
-               ar_pci->pipe_info[i].ar_pci = ar_pci;
-               tasklet_init(&ar_pci->pipe_info[i].intr, ath10k_pci_ce_tasklet,
-                            (unsigned long)&ar_pci->pipe_info[i]);
-       }
 }
 
 static int ath10k_pci_init_irq(struct ath10k *ar)
@@ -2822,20 +2701,9 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
                ath10k_info(ar, "limiting irq mode to: %d\n",
                            ath10k_pci_irq_mode);
 
-       /* Try MSI-X */
-       if (ath10k_pci_irq_mode == ATH10K_PCI_IRQ_AUTO) {
-               ar_pci->num_msi_intrs = MSI_ASSIGN_CE_MAX + 1;
-               ret = pci_enable_msi_range(ar_pci->pdev, ar_pci->num_msi_intrs,
-                                          ar_pci->num_msi_intrs);
-               if (ret > 0)
-                       return 0;
-
-               /* fall-through */
-       }
-
        /* Try MSI */
        if (ath10k_pci_irq_mode != ATH10K_PCI_IRQ_LEGACY) {
-               ar_pci->num_msi_intrs = 1;
+               ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_MSI;
                ret = pci_enable_msi(ar_pci->pdev);
                if (ret == 0)
                        return 0;
@@ -2851,7 +2719,7 @@ static int ath10k_pci_init_irq(struct ath10k *ar)
         * This write might get lost if target has NOT written BAR.
         * For now, fix the race by repeating the write in below
         * synchronization checking. */
-       ar_pci->num_msi_intrs = 0;
+       ar_pci->oper_irq_mode = ATH10K_PCI_IRQ_LEGACY;
 
        ath10k_pci_write32(ar, SOC_CORE_BASE_ADDRESS + PCIE_INTR_ENABLE_ADDRESS,
                           PCIE_INTR_FIRMWARE_MASK | PCIE_INTR_CE_MASK_ALL);
@@ -2869,8 +2737,8 @@ static int ath10k_pci_deinit_irq(struct ath10k *ar)
 {
        struct ath10k_pci *ar_pci = ath10k_pci_priv(ar);
 
-       switch (ar_pci->num_msi_intrs) {
-       case 0:
+       switch (ar_pci->oper_irq_mode) {
+       case ATH10K_PCI_IRQ_LEGACY:
                ath10k_pci_deinit_irq_legacy(ar);
                break;
        default:
@@ -2908,7 +2776,7 @@ int ath10k_pci_wait_for_target_init(struct ath10k *ar)
                if (val & FW_IND_INITIALIZED)
                        break;
 
-               if (ar_pci->num_msi_intrs == 0)
+               if (ar_pci->oper_irq_mode == ATH10K_PCI_IRQ_LEGACY)
                        /* Fix potential race by repeating CORE_BASE writes */
                        ath10k_pci_enable_legacy_irq(ar);
 
@@ -3186,8 +3054,8 @@ static int ath10k_pci_probe(struct pci_dev *pdev,
                goto err_sleep;
        }
 
-       ath10k_info(ar, "pci irq %s interrupts %d irq_mode %d reset_mode %d\n",
-                   ath10k_pci_get_irq_method(ar), ar_pci->num_msi_intrs,
+       ath10k_info(ar, "pci irq %s oper_irq_mode %d irq_mode %d reset_mode %d\n",
+                   ath10k_pci_get_irq_method(ar), ar_pci->oper_irq_mode,
                    ath10k_pci_irq_mode, ath10k_pci_reset_mode);
 
        ret = ath10k_pci_request_irq(ar);
@@ -3305,7 +3173,6 @@ MODULE_DESCRIPTION("Driver support for Atheros QCA988X PCIe devices");
 MODULE_LICENSE("Dual BSD/GPL");
 
 /* QCA988x 2.0 firmware files */
-MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" QCA988X_HW_2_0_FW_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API2_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API3_FILE);
 MODULE_FIRMWARE(QCA988X_HW_2_0_FW_DIR "/" ATH10K_FW_API4_FILE);
index 249c73a..959dc32 100644 (file)
@@ -148,9 +148,6 @@ struct ath10k_pci_pipe {
 
        /* protects compl_free and num_send_allowed */
        spinlock_t pipe_lock;
-
-       struct ath10k_pci *ar_pci;
-       struct tasklet_struct intr;
 };
 
 struct ath10k_pci_supp_chip {
@@ -164,6 +161,12 @@ struct ath10k_bus_ops {
        int (*get_num_banks)(struct ath10k *ar);
 };
 
+enum ath10k_pci_irq_mode {
+       ATH10K_PCI_IRQ_AUTO = 0,
+       ATH10K_PCI_IRQ_LEGACY = 1,
+       ATH10K_PCI_IRQ_MSI = 2,
+};
+
 struct ath10k_pci {
        struct pci_dev *pdev;
        struct device *dev;
@@ -171,14 +174,10 @@ struct ath10k_pci {
        void __iomem *mem;
        size_t mem_len;
 
-       /*
-        * Number of MSI interrupts granted, 0 --> using legacy PCI line
-        * interrupts.
-        */
-       int num_msi_intrs;
+       /* Operating interrupt mode */
+       enum ath10k_pci_irq_mode oper_irq_mode;
 
        struct tasklet_struct intr_tq;
-       struct tasklet_struct msi_fw_err;
 
        struct ath10k_pci_pipe pipe_info[CE_COUNT_MAX];
 
index 3ca3fae..0c5f586 100644 (file)
@@ -134,27 +134,17 @@ ath10k_swap_code_seg_alloc(struct ath10k *ar, size_t swap_bin_len)
        return seg_info;
 }
 
-int ath10k_swap_code_seg_configure(struct ath10k *ar,
-                                  enum ath10k_swap_code_seg_bin_type type)
+int ath10k_swap_code_seg_configure(struct ath10k *ar)
 {
        int ret;
        struct ath10k_swap_code_seg_info *seg_info = NULL;
 
-       switch (type) {
-       case ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW:
-               if (!ar->swap.firmware_swap_code_seg_info)
-                       return 0;
-
-               ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot found firmware code swap binary\n");
-               seg_info = ar->swap.firmware_swap_code_seg_info;
-               break;
-       default:
-       case ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP:
-       case ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF:
-               ath10k_warn(ar, "ignoring unknown code swap binary type %d\n",
-                           type);
+       if (!ar->swap.firmware_swap_code_seg_info)
                return 0;
-       }
+
+       ath10k_dbg(ar, ATH10K_DBG_BOOT, "boot found firmware code swap binary\n");
+
+       seg_info = ar->swap.firmware_swap_code_seg_info;
 
        ret = ath10k_bmi_write_memory(ar, seg_info->target_addr,
                                      &seg_info->seg_hw_info,
@@ -171,8 +161,13 @@ int ath10k_swap_code_seg_configure(struct ath10k *ar,
 void ath10k_swap_code_seg_release(struct ath10k *ar)
 {
        ath10k_swap_code_seg_free(ar, ar->swap.firmware_swap_code_seg_info);
-       ar->swap.firmware_codeswap_data = NULL;
-       ar->swap.firmware_codeswap_len = 0;
+
+       /* FIXME: these two assignments look to bein wrong place! Shouldn't
+        * they be in ath10k_core_free_firmware_files() like the rest?
+        */
+       ar->normal_mode_fw.fw_file.codeswap_data = NULL;
+       ar->normal_mode_fw.fw_file.codeswap_len = 0;
+
        ar->swap.firmware_swap_code_seg_info = NULL;
 }
 
@@ -180,20 +175,23 @@ int ath10k_swap_code_seg_init(struct ath10k *ar)
 {
        int ret;
        struct ath10k_swap_code_seg_info *seg_info;
+       const void *codeswap_data;
+       size_t codeswap_len;
+
+       codeswap_data = ar->normal_mode_fw.fw_file.codeswap_data;
+       codeswap_len = ar->normal_mode_fw.fw_file.codeswap_len;
 
-       if (!ar->swap.firmware_codeswap_len || !ar->swap.firmware_codeswap_data)
+       if (!codeswap_len || !codeswap_data)
                return 0;
 
-       seg_info = ath10k_swap_code_seg_alloc(ar,
-                                             ar->swap.firmware_codeswap_len);
+       seg_info = ath10k_swap_code_seg_alloc(ar, codeswap_len);
        if (!seg_info) {
                ath10k_err(ar, "failed to allocate fw code swap segment\n");
                return -ENOMEM;
        }
 
        ret = ath10k_swap_code_seg_fill(ar, seg_info,
-                                       ar->swap.firmware_codeswap_data,
-                                       ar->swap.firmware_codeswap_len);
+                                       codeswap_data, codeswap_len);
 
        if (ret) {
                ath10k_warn(ar, "failed to initialize fw code swap segment: %d\n",
index 5c89952..36991c7 100644 (file)
@@ -39,12 +39,6 @@ union ath10k_swap_code_seg_item {
        struct ath10k_swap_code_seg_tail tail;
 } __packed;
 
-enum ath10k_swap_code_seg_bin_type {
-        ATH10K_SWAP_CODE_SEG_BIN_TYPE_OTP,
-        ATH10K_SWAP_CODE_SEG_BIN_TYPE_FW,
-        ATH10K_SWAP_CODE_SEG_BIN_TYPE_UTF,
-};
-
 struct ath10k_swap_code_seg_hw_info {
        /* Swap binary image size */
        __le32 swap_size;
@@ -64,8 +58,7 @@ struct ath10k_swap_code_seg_info {
        dma_addr_t paddr[ATH10K_SWAP_CODE_SEG_NUM_SUPPORTED];
 };
 
-int ath10k_swap_code_seg_configure(struct ath10k *ar,
-                                  enum ath10k_swap_code_seg_bin_type type);
+int ath10k_swap_code_seg_configure(struct ath10k *ar);
 void ath10k_swap_code_seg_release(struct ath10k *ar);
 int ath10k_swap_code_seg_init(struct ath10k *ar);
 
index 361f143..8e24099 100644 (file)
@@ -438,7 +438,7 @@ Fw Mode/SubMode Mask
        ((HOST_INTEREST->hi_pwr_save_flags & HI_PWR_SAVE_LPL_ENABLED))
 #define HI_DEV_LPL_TYPE_GET(_devix) \
        (HOST_INTEREST->hi_pwr_save_flags & ((HI_PWR_SAVE_LPL_DEV_MASK) << \
-        (HI_PWR_SAVE_LPL_DEV0_LSB + (_devix)*2)))
+        (HI_PWR_SAVE_LPL_DEV0_LSB + (_devix) * 2)))
 
 #define HOST_INTEREST_SMPS_IS_ALLOWED() \
        ((HOST_INTEREST->hi_smps_options & HI_SMPS_ALLOW_MASK))
index 1d5a2fd..120f423 100644 (file)
@@ -139,127 +139,8 @@ static int ath10k_tm_cmd_get_version(struct ath10k *ar, struct nlattr *tb[])
        return cfg80211_testmode_reply(skb);
 }
 
-static int ath10k_tm_fetch_utf_firmware_api_2(struct ath10k *ar)
-{
-       size_t len, magic_len, ie_len;
-       struct ath10k_fw_ie *hdr;
-       char filename[100];
-       __le32 *version;
-       const u8 *data;
-       int ie_id, ret;
-
-       snprintf(filename, sizeof(filename), "%s/%s",
-                ar->hw_params.fw.dir, ATH10K_FW_UTF_API2_FILE);
-
-       /* load utf firmware image */
-       ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
-       if (ret) {
-               ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
-                           filename, ret);
-               return ret;
-       }
-
-       data = ar->testmode.utf->data;
-       len = ar->testmode.utf->size;
-
-       /* FIXME: call release_firmware() in error cases */
-
-       /* magic also includes the null byte, check that as well */
-       magic_len = strlen(ATH10K_FIRMWARE_MAGIC) + 1;
-
-       if (len < magic_len) {
-               ath10k_err(ar, "utf firmware file is too small to contain magic\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       if (memcmp(data, ATH10K_FIRMWARE_MAGIC, magic_len) != 0) {
-               ath10k_err(ar, "invalid firmware magic\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       /* jump over the padding */
-       magic_len = ALIGN(magic_len, 4);
-
-       len -= magic_len;
-       data += magic_len;
-
-       /* loop elements */
-       while (len > sizeof(struct ath10k_fw_ie)) {
-               hdr = (struct ath10k_fw_ie *)data;
-
-               ie_id = le32_to_cpu(hdr->id);
-               ie_len = le32_to_cpu(hdr->len);
-
-               len -= sizeof(*hdr);
-               data += sizeof(*hdr);
-
-               if (len < ie_len) {
-                       ath10k_err(ar, "invalid length for FW IE %d (%zu < %zu)\n",
-                                  ie_id, len, ie_len);
-                       ret = -EINVAL;
-                       goto err;
-               }
-
-               switch (ie_id) {
-               case ATH10K_FW_IE_FW_VERSION:
-                       if (ie_len > sizeof(ar->testmode.utf_version) - 1)
-                               break;
-
-                       memcpy(ar->testmode.utf_version, data, ie_len);
-                       ar->testmode.utf_version[ie_len] = '\0';
-
-                       ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
-                                  "testmode found fw utf version %s\n",
-                                  ar->testmode.utf_version);
-                       break;
-               case ATH10K_FW_IE_TIMESTAMP:
-                       /* ignore timestamp, but don't warn about it either */
-                       break;
-               case ATH10K_FW_IE_FW_IMAGE:
-                       ath10k_dbg(ar, ATH10K_DBG_TESTMODE,
-                                  "testmode found fw image ie (%zd B)\n",
-                                  ie_len);
-
-                       ar->testmode.utf_firmware_data = data;
-                       ar->testmode.utf_firmware_len = ie_len;
-                       break;
-               case ATH10K_FW_IE_WMI_OP_VERSION:
-                       if (ie_len != sizeof(u32))
-                               break;
-                       version = (__le32 *)data;
-                       ar->testmode.op_version = le32_to_cpup(version);
-                       ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode found fw ie wmi op version %d\n",
-                                  ar->testmode.op_version);
-                       break;
-               default:
-                       ath10k_warn(ar, "Unknown testmode FW IE: %u\n",
-                                   le32_to_cpu(hdr->id));
-                       break;
-               }
-               /* jump over the padding */
-               ie_len = ALIGN(ie_len, 4);
-
-               len -= ie_len;
-               data += ie_len;
-       }
-
-       if (!ar->testmode.utf_firmware_data || !ar->testmode.utf_firmware_len) {
-               ath10k_err(ar, "No ATH10K_FW_IE_FW_IMAGE found\n");
-               ret = -EINVAL;
-               goto err;
-       }
-
-       return 0;
-
-err:
-       release_firmware(ar->testmode.utf);
-
-       return ret;
-}
-
-static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar)
+static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar,
+                                             struct ath10k_fw_file *fw_file)
 {
        char filename[100];
        int ret;
@@ -268,7 +149,7 @@ static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar)
                 ar->hw_params.fw.dir, ATH10K_FW_UTF_FILE);
 
        /* load utf firmware image */
-       ret = request_firmware(&ar->testmode.utf, filename, ar->dev);
+       ret = request_firmware(&fw_file->firmware, filename, ar->dev);
        if (ret) {
                ath10k_warn(ar, "failed to retrieve utf firmware '%s': %d\n",
                            filename, ret);
@@ -281,24 +162,27 @@ static int ath10k_tm_fetch_utf_firmware_api_1(struct ath10k *ar)
         * correct WMI interface.
         */
 
-       ar->testmode.op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
-       ar->testmode.utf_firmware_data = ar->testmode.utf->data;
-       ar->testmode.utf_firmware_len = ar->testmode.utf->size;
+       fw_file->wmi_op_version = ATH10K_FW_WMI_OP_VERSION_10_1;
+       fw_file->htt_op_version = ATH10K_FW_HTT_OP_VERSION_10_1;
+       fw_file->firmware_data = fw_file->firmware->data;
+       fw_file->firmware_len = fw_file->firmware->size;
 
        return 0;
 }
 
 static int ath10k_tm_fetch_firmware(struct ath10k *ar)
 {
+       struct ath10k_fw_components *utf_mode_fw;
        int ret;
 
-       ret = ath10k_tm_fetch_utf_firmware_api_2(ar);
+       ret = ath10k_core_fetch_firmware_api_n(ar, ATH10K_FW_UTF_API2_FILE,
+                                              &ar->testmode.utf_mode_fw.fw_file);
        if (ret == 0) {
                ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using fw utf api 2");
-               return 0;
+               goto out;
        }
 
-       ret = ath10k_tm_fetch_utf_firmware_api_1(ar);
+       ret = ath10k_tm_fetch_utf_firmware_api_1(ar, &ar->testmode.utf_mode_fw.fw_file);
        if (ret) {
                ath10k_err(ar, "failed to fetch utf firmware binary: %d", ret);
                return ret;
@@ -306,6 +190,21 @@ static int ath10k_tm_fetch_firmware(struct ath10k *ar)
 
        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode using utf api 1");
 
+out:
+       utf_mode_fw = &ar->testmode.utf_mode_fw;
+
+       /* Use the same board data file as the normal firmware uses (but
+        * it's still "owned" by normal_mode_fw so we shouldn't free it.
+        */
+       utf_mode_fw->board_data = ar->normal_mode_fw.board_data;
+       utf_mode_fw->board_len = ar->normal_mode_fw.board_len;
+
+       if (!utf_mode_fw->fw_file.otp_data) {
+               ath10k_info(ar, "utf.bin didn't contain otp binary, taking it from the normal mode firmware");
+               utf_mode_fw->fw_file.otp_data = ar->normal_mode_fw.fw_file.otp_data;
+               utf_mode_fw->fw_file.otp_len = ar->normal_mode_fw.fw_file.otp_len;
+       }
+
        return 0;
 }
 
@@ -329,7 +228,7 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
                goto err;
        }
 
-       if (WARN_ON(ar->testmode.utf != NULL)) {
+       if (WARN_ON(ar->testmode.utf_mode_fw.fw_file.firmware != NULL)) {
                /* utf image is already downloaded, it shouldn't be */
                ret = -EEXIST;
                goto err;
@@ -344,27 +243,19 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
        spin_lock_bh(&ar->data_lock);
        ar->testmode.utf_monitor = true;
        spin_unlock_bh(&ar->data_lock);
-       BUILD_BUG_ON(sizeof(ar->fw_features) !=
-                    sizeof(ar->testmode.orig_fw_features));
-
-       memcpy(ar->testmode.orig_fw_features, ar->fw_features,
-              sizeof(ar->fw_features));
-       ar->testmode.orig_wmi_op_version = ar->wmi.op_version;
-       memset(ar->fw_features, 0, sizeof(ar->fw_features));
-
-       ar->wmi.op_version = ar->testmode.op_version;
 
        ath10k_dbg(ar, ATH10K_DBG_TESTMODE, "testmode wmi version %d\n",
-                  ar->wmi.op_version);
+                  ar->testmode.utf_mode_fw.fw_file.wmi_op_version);
 
        ret = ath10k_hif_power_up(ar);
        if (ret) {
                ath10k_err(ar, "failed to power up hif (testmode): %d\n", ret);
                ar->state = ATH10K_STATE_OFF;
-               goto err_fw_features;
+               goto err_release_utf_mode_fw;
        }
 
-       ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF);
+       ret = ath10k_core_start(ar, ATH10K_FIRMWARE_MODE_UTF,
+                               &ar->testmode.utf_mode_fw);
        if (ret) {
                ath10k_err(ar, "failed to start core (testmode): %d\n", ret);
                ar->state = ATH10K_STATE_OFF;
@@ -373,8 +264,8 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
 
        ar->state = ATH10K_STATE_UTF;
 
-       if (strlen(ar->testmode.utf_version) > 0)
-               ver = ar->testmode.utf_version;
+       if (strlen(ar->testmode.utf_mode_fw.fw_file.fw_version) > 0)
+               ver = ar->testmode.utf_mode_fw.fw_file.fw_version;
        else
                ver = "API 1";
 
@@ -387,14 +278,9 @@ static int ath10k_tm_cmd_utf_start(struct ath10k *ar, struct nlattr *tb[])
 err_power_down:
        ath10k_hif_power_down(ar);
 
-err_fw_features:
-       /* return the original firmware features */
-       memcpy(ar->fw_features, ar->testmode.orig_fw_features,
-              sizeof(ar->fw_features));
-       ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
-
-       release_firmware(ar->testmode.utf);
-       ar->testmode.utf = NULL;
+err_release_utf_mode_fw:
+       release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
+       ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
 
 err:
        mutex_unlock(&ar->conf_mutex);
@@ -415,13 +301,8 @@ static void __ath10k_tm_cmd_utf_stop(struct ath10k *ar)
 
        spin_unlock_bh(&ar->data_lock);
 
-       /* return the original firmware features */
-       memcpy(ar->fw_features, ar->testmode.orig_fw_features,
-              sizeof(ar->fw_features));
-       ar->wmi.op_version = ar->testmode.orig_wmi_op_version;
-
-       release_firmware(ar->testmode.utf);
-       ar->testmode.utf = NULL;
+       release_firmware(ar->testmode.utf_mode_fw.fw_file.firmware);
+       ar->testmode.utf_mode_fw.fw_file.firmware = NULL;
 
        ar->state = ATH10K_STATE_OFF;
 }
index c9223e9..3abb97f 100644 (file)
@@ -20,7 +20,7 @@
 #define ATH10K_QUIET_PERIOD_MIN         25
 #define ATH10K_QUIET_START_OFFSET       10
 #define ATH10K_HWMON_NAME_LEN           15
-#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5*HZ)
+#define ATH10K_THERMAL_SYNC_TIMEOUT_HZ (5 * HZ)
 #define ATH10K_THERMAL_THROTTLE_MAX     100
 
 struct ath10k_thermal {
index 9369411..576e7c4 100644 (file)
@@ -130,7 +130,7 @@ struct ath10k_peer *ath10k_peer_find(struct ath10k *ar, int vdev_id,
        list_for_each_entry(peer, &ar->peers, list) {
                if (peer->vdev_id != vdev_id)
                        continue;
-               if (memcmp(peer->addr, addr, ETH_ALEN))
+               if (!ether_addr_equal(peer->addr, addr))
                        continue;
 
                return peer;
@@ -166,7 +166,7 @@ static int ath10k_wait_for_peer_common(struct ath10k *ar, int vdev_id,
 
                        (mapped == expect_mapped ||
                         test_bit(ATH10K_FLAG_CRASH_FLUSH, &ar->dev_flags));
-               }), 3*HZ);
+               }), 3 * HZ);
 
        if (time_left == 0)
                return -ETIMEDOUT;
@@ -190,6 +190,13 @@ void ath10k_peer_map_event(struct ath10k_htt *htt,
        struct ath10k *ar = htt->ar;
        struct ath10k_peer *peer;
 
+       if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) {
+               ath10k_warn(ar,
+                           "received htt peer map event with idx out of bounds: %hu\n",
+                           ev->peer_id);
+               return;
+       }
+
        spin_lock_bh(&ar->data_lock);
        peer = ath10k_peer_find(ar, ev->vdev_id, ev->addr);
        if (!peer) {
@@ -218,6 +225,13 @@ void ath10k_peer_unmap_event(struct ath10k_htt *htt,
        struct ath10k *ar = htt->ar;
        struct ath10k_peer *peer;
 
+       if (ev->peer_id >= ATH10K_MAX_NUM_PEER_IDS) {
+               ath10k_warn(ar,
+                           "received htt peer unmap event with idx out of bounds: %hu\n",
+                           ev->peer_id);
+               return;
+       }
+
        spin_lock_bh(&ar->data_lock);
        peer = ath10k_peer_find_by_id(ar, ev->peer_id);
        if (!peer) {
index 1085932..e09337e 100644 (file)
@@ -3409,6 +3409,7 @@ static struct wmi_vdev_param_map wmi_tlv_vdev_param_map = {
        .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED,
        .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED,
        .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,
+       .set_tsf = WMI_VDEV_PARAM_UNSUPPORTED,
 };
 
 static const struct wmi_ops wmi_tlv_ops = {
index dd67859..b8aa600 100644 (file)
@@ -968,8 +968,8 @@ enum wmi_tlv_service {
 
 #define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
        ((svc_id) < (len) && \
-        __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
-        BIT((svc_id)%(sizeof(u32))))
+        __le32_to_cpu((wmi_svc_bmap)[(svc_id) / (sizeof(u32))]) & \
+        BIT((svc_id) % (sizeof(u32))))
 
 #define SVCMAP(x, y, len) \
        do { \
index 4c75c74..621019f 100644 (file)
@@ -781,6 +781,7 @@ static struct wmi_vdev_param_map wmi_vdev_param_map = {
        .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED,
        .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED,
        .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,
+       .set_tsf = WMI_VDEV_PARAM_UNSUPPORTED,
 };
 
 /* 10.X WMI VDEV param map */
@@ -856,6 +857,7 @@ static struct wmi_vdev_param_map wmi_10x_vdev_param_map = {
        .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED,
        .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED,
        .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,
+       .set_tsf = WMI_VDEV_PARAM_UNSUPPORTED,
 };
 
 static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = {
@@ -930,6 +932,7 @@ static struct wmi_vdev_param_map wmi_10_2_4_vdev_param_map = {
        .meru_vc = WMI_VDEV_PARAM_UNSUPPORTED,
        .rx_decap_type = WMI_VDEV_PARAM_UNSUPPORTED,
        .bw_nss_ratemask = WMI_VDEV_PARAM_UNSUPPORTED,
+       .set_tsf = WMI_10X_VDEV_PARAM_TSF_INCREMENT,
 };
 
 static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = {
@@ -1005,6 +1008,7 @@ static struct wmi_vdev_param_map wmi_10_4_vdev_param_map = {
        .meru_vc = WMI_10_4_VDEV_PARAM_MERU_VC,
        .rx_decap_type = WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE,
        .bw_nss_ratemask = WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK,
+       .set_tsf = WMI_10_4_VDEV_PARAM_TSF_INCREMENT,
 };
 
 static struct wmi_pdev_param_map wmi_pdev_param_map = {
@@ -1804,7 +1808,7 @@ int ath10k_wmi_cmd_send(struct ath10k *ar, struct sk_buff *skb, u32 cmd_id)
                        ret = -ESHUTDOWN;
 
                (ret != -EAGAIN);
-       }), 3*HZ);
+       }), 3 * HZ);
 
        if (ret)
                dev_kfree_skb_any(skb);
@@ -2145,7 +2149,8 @@ static int ath10k_wmi_op_pull_mgmt_rx_ev(struct ath10k *ar, struct sk_buff *skb,
        u32 msdu_len;
        u32 len;
 
-       if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features)) {
+       if (test_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX,
+                    ar->running_fw->fw_file.fw_features)) {
                ev_v2 = (struct wmi_mgmt_rx_event_v2 *)skb->data;
                ev_hdr = &ev_v2->hdr.v1;
                pull_len = sizeof(*ev_v2);
@@ -4600,10 +4605,6 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
        ath10k_dbg_dump(ar, ATH10K_DBG_WMI, NULL, "wmi svc: ",
                        arg.service_map, arg.service_map_len);
 
-       /* only manually set fw features when not using FW IE format */
-       if (ar->fw_api == 1 && ar->fw_version_build > 636)
-               set_bit(ATH10K_FW_FEATURE_EXT_WMI_MGMT_RX, ar->fw_features);
-
        if (ar->num_rf_chains > ar->max_spatial_stream) {
                ath10k_warn(ar, "hardware advertises support for more spatial streams than it should (%d > %d)\n",
                            ar->num_rf_chains, ar->max_spatial_stream);
@@ -4634,7 +4635,7 @@ static void ath10k_wmi_event_service_ready_work(struct work_struct *work)
 
        if (test_bit(WMI_SERVICE_PEER_CACHING, ar->wmi.svc_map)) {
                if (test_bit(ATH10K_FW_FEATURE_PEER_FLOW_CONTROL,
-                            ar->fw_features))
+                            ar->running_fw->fw_file.fw_features))
                        ar->num_active_peers = TARGET_10_4_QCACHE_ACTIVE_PEERS_PFC +
                                               ar->max_num_vdevs;
                else
@@ -5823,9 +5824,8 @@ ath10k_wmi_put_start_scan_tlvs(struct wmi_start_scan_tlvs *tlvs,
                bssids->num_bssid = __cpu_to_le32(arg->n_bssids);
 
                for (i = 0; i < arg->n_bssids; i++)
-                       memcpy(&bssids->bssid_list[i],
-                              arg->bssids[i].bssid,
-                              ETH_ALEN);
+                       ether_addr_copy(bssids->bssid_list[i].addr,
+                                       arg->bssids[i].bssid);
 
                ptr += sizeof(*bssids);
                ptr += sizeof(struct wmi_mac_addr) * arg->n_bssids;
@@ -7865,7 +7865,7 @@ static const struct wmi_ops wmi_10_4_ops = {
 
 int ath10k_wmi_attach(struct ath10k *ar)
 {
-       switch (ar->wmi.op_version) {
+       switch (ar->running_fw->fw_file.wmi_op_version) {
        case ATH10K_FW_WMI_OP_VERSION_10_4:
                ar->wmi.ops = &wmi_10_4_ops;
                ar->wmi.cmd = &wmi_10_4_cmd_map;
@@ -7907,7 +7907,7 @@ int ath10k_wmi_attach(struct ath10k *ar)
        case ATH10K_FW_WMI_OP_VERSION_UNSET:
        case ATH10K_FW_WMI_OP_VERSION_MAX:
                ath10k_err(ar, "unsupported WMI op version: %d\n",
-                          ar->wmi.op_version);
+                          ar->running_fw->fw_file.wmi_op_version);
                return -EINVAL;
        }
 
index feebd19..db25535 100644 (file)
@@ -180,6 +180,9 @@ enum wmi_service {
        WMI_SERVICE_MESH_NON_11S,
        WMI_SERVICE_PEER_STATS,
        WMI_SERVICE_RESTRT_CHNL_SUPPORT,
+       WMI_SERVICE_TX_MODE_PUSH_ONLY,
+       WMI_SERVICE_TX_MODE_PUSH_PULL,
+       WMI_SERVICE_TX_MODE_DYNAMIC,
 
        /* keep last */
        WMI_SERVICE_MAX,
@@ -302,6 +305,9 @@ enum wmi_10_4_service {
        WMI_10_4_SERVICE_RESTRT_CHNL_SUPPORT,
        WMI_10_4_SERVICE_PEER_STATS,
        WMI_10_4_SERVICE_MESH_11S,
+       WMI_10_4_SERVICE_TX_MODE_PUSH_ONLY,
+       WMI_10_4_SERVICE_TX_MODE_PUSH_PULL,
+       WMI_10_4_SERVICE_TX_MODE_DYNAMIC,
 };
 
 static inline char *wmi_service_name(int service_id)
@@ -396,6 +402,9 @@ static inline char *wmi_service_name(int service_id)
        SVCSTR(WMI_SERVICE_MESH_NON_11S);
        SVCSTR(WMI_SERVICE_PEER_STATS);
        SVCSTR(WMI_SERVICE_RESTRT_CHNL_SUPPORT);
+       SVCSTR(WMI_SERVICE_TX_MODE_PUSH_ONLY);
+       SVCSTR(WMI_SERVICE_TX_MODE_PUSH_PULL);
+       SVCSTR(WMI_SERVICE_TX_MODE_DYNAMIC);
        default:
                return NULL;
        }
@@ -405,8 +414,8 @@ static inline char *wmi_service_name(int service_id)
 
 #define WMI_SERVICE_IS_ENABLED(wmi_svc_bmap, svc_id, len) \
        ((svc_id) < (len) && \
-        __le32_to_cpu((wmi_svc_bmap)[(svc_id)/(sizeof(u32))]) & \
-        BIT((svc_id)%(sizeof(u32))))
+        __le32_to_cpu((wmi_svc_bmap)[(svc_id) / (sizeof(u32))]) & \
+        BIT((svc_id) % (sizeof(u32))))
 
 #define SVCMAP(x, y, len) \
        do { \
@@ -643,6 +652,12 @@ static inline void wmi_10_4_svc_map(const __le32 *in, unsigned long *out,
               WMI_SERVICE_PEER_STATS, len);
        SVCMAP(WMI_10_4_SERVICE_MESH_11S,
               WMI_SERVICE_MESH_11S, len);
+       SVCMAP(WMI_10_4_SERVICE_TX_MODE_PUSH_ONLY,
+              WMI_SERVICE_TX_MODE_PUSH_ONLY, len);
+       SVCMAP(WMI_10_4_SERVICE_TX_MODE_PUSH_PULL,
+              WMI_SERVICE_TX_MODE_PUSH_PULL, len);
+       SVCMAP(WMI_10_4_SERVICE_TX_MODE_DYNAMIC,
+              WMI_SERVICE_TX_MODE_DYNAMIC, len);
 }
 
 #undef SVCMAP
@@ -1309,7 +1324,7 @@ enum wmi_10x_event_id {
        WMI_10X_PDEV_TPC_CONFIG_EVENTID,
 
        WMI_10X_GPIO_INPUT_EVENTID,
-       WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID-1,
+       WMI_10X_PDEV_UTF_EVENTID = WMI_10X_END_EVENTID - 1,
 };
 
 enum wmi_10_2_cmd_id {
@@ -2042,8 +2057,8 @@ struct wmi_10x_service_ready_event {
        struct wlan_host_mem_req mem_reqs[0];
 } __packed;
 
-#define WMI_SERVICE_READY_TIMEOUT_HZ (5*HZ)
-#define WMI_UNIFIED_READY_TIMEOUT_HZ (5*HZ)
+#define WMI_SERVICE_READY_TIMEOUT_HZ (5 * HZ)
+#define WMI_UNIFIED_READY_TIMEOUT_HZ (5 * HZ)
 
 struct wmi_ready_event {
        __le32 sw_version;
@@ -2661,9 +2676,14 @@ struct wmi_resource_config_10_4 {
         */
        __le32 iphdr_pad_config;
 
-       /* qwrap configuration
+       /* qwrap configuration (bits 15-0)
         * 1  - This is qwrap configuration
         * 0  - This is not qwrap
+        *
+        * Bits 31-16 is alloc_frag_desc_for_data_pkt (1 enables, 0 disables)
+        * In order to get ack-RSSI reporting and to specify the tx-rate for
+        * individual frames, this option must be enabled.  This uses an extra
+        * 4 bytes per tx-msdu descriptor, so don't enable it unless you need it.
         */
        __le32 qwrap_config;
 } __packed;
@@ -4384,14 +4404,14 @@ enum wmi_vdev_subtype_10_4 {
 /*
  * Indicates that AP VDEV uses hidden ssid. only valid for
  *  AP/GO */
-#define WMI_VDEV_START_HIDDEN_SSID  (1<<0)
+#define WMI_VDEV_START_HIDDEN_SSID  (1 << 0)
 /*
  * Indicates if robust management frame/management frame
  *  protection is enabled. For GO/AP vdevs, it indicates that
  *  it may support station/client associations with RMF enabled.
  *  For STA/client vdevs, it indicates that sta will
  *  associate with AP with RMF enabled. */
-#define WMI_VDEV_START_PMF_ENABLED  (1<<1)
+#define WMI_VDEV_START_PMF_ENABLED  (1 << 1)
 
 struct wmi_p2p_noa_descriptor {
        __le32 type_count; /* 255: continuous schedule, 0: reserved */
@@ -4630,6 +4650,7 @@ struct wmi_vdev_param_map {
        u32 meru_vc;
        u32 rx_decap_type;
        u32 bw_nss_ratemask;
+       u32 set_tsf;
 };
 
 #define WMI_VDEV_PARAM_UNSUPPORTED 0
@@ -4886,6 +4907,7 @@ enum wmi_10x_vdev_param {
        WMI_10X_VDEV_PARAM_RTS_FIXED_RATE,
        WMI_10X_VDEV_PARAM_VHT_SGIMASK,
        WMI_10X_VDEV_PARAM_VHT80_RATEMASK,
+       WMI_10X_VDEV_PARAM_TSF_INCREMENT,
 };
 
 enum wmi_10_4_vdev_param {
@@ -4955,6 +4977,12 @@ enum wmi_10_4_vdev_param {
        WMI_10_4_VDEV_PARAM_MERU_VC,
        WMI_10_4_VDEV_PARAM_RX_DECAP_TYPE,
        WMI_10_4_VDEV_PARAM_BW_NSS_RATEMASK,
+       WMI_10_4_VDEV_PARAM_SENSOR_AP,
+       WMI_10_4_VDEV_PARAM_BEACON_RATE,
+       WMI_10_4_VDEV_PARAM_DTIM_ENABLE_CTS,
+       WMI_10_4_VDEV_PARAM_STA_KICKOUT,
+       WMI_10_4_VDEV_PARAM_CAPABILITIES,
+       WMI_10_4_VDEV_PARAM_TSF_INCREMENT,
 };
 
 #define WMI_VDEV_PARAM_TXBF_SU_TX_BFEE BIT(0)
@@ -5329,7 +5357,7 @@ enum wmi_sta_ps_param_pspoll_count {
 #define WMI_UAPSD_AC_TYPE_TRIG 1
 
 #define WMI_UAPSD_AC_BIT_MASK(ac, type) \
-       ((type ==  WMI_UAPSD_AC_TYPE_DELI) ? (1<<(ac<<1)) : (1<<((ac<<1)+1)))
+       ((type ==  WMI_UAPSD_AC_TYPE_DELI) ? (1 << (ac << 1)) : (1 << ((ac << 1) + 1)))
 
 enum wmi_sta_ps_param_uapsd {
        WMI_STA_PS_UAPSD_AC0_DELIVERY_EN = (1 << 0),
@@ -5744,7 +5772,7 @@ struct wmi_rate_set {
         * the rates are filled from least significant byte to most
         * significant byte.
         */
-       __le32 rates[(MAX_SUPPORTED_RATES/4)+1];
+       __le32 rates[(MAX_SUPPORTED_RATES / 4) + 1];
 } __packed;
 
 struct wmi_rate_set_arg {
index 8e02b38..77100d4 100644 (file)
@@ -233,7 +233,7 @@ int ath10k_wow_op_suspend(struct ieee80211_hw *hw,
        mutex_lock(&ar->conf_mutex);
 
        if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
-                             ar->fw_features))) {
+                             ar->running_fw->fw_file.fw_features))) {
                ret = 1;
                goto exit;
        }
@@ -285,7 +285,7 @@ int ath10k_wow_op_resume(struct ieee80211_hw *hw)
        mutex_lock(&ar->conf_mutex);
 
        if (WARN_ON(!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
-                             ar->fw_features))) {
+                             ar->running_fw->fw_file.fw_features))) {
                ret = 1;
                goto exit;
        }
@@ -325,7 +325,8 @@ exit:
 
 int ath10k_wow_init(struct ath10k *ar)
 {
-       if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT, ar->fw_features))
+       if (!test_bit(ATH10K_FW_FEATURE_WOWLAN_SUPPORT,
+                     ar->running_fw->fw_file.fw_features))
                return 0;
 
        if (WARN_ON(!test_bit(WMI_SERVICE_WOW, ar->wmi.svc_map)))
index 8a8d785..a553c91 100644 (file)
@@ -246,7 +246,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
        struct ieee80211_conf *conf = &common->hw->conf;
        bool fastcc;
        struct ieee80211_channel *channel = hw->conf.chandef.chan;
-       struct ath9k_hw_cal_data *caldata = NULL;
+       struct ath9k_hw_cal_data *caldata;
        enum htc_phymode mode;
        __be16 htc_mode;
        u8 cmd_rsp;
@@ -274,10 +274,7 @@ static int ath9k_htc_set_channel(struct ath9k_htc_priv *priv,
                priv->ah->curchan->channel,
                channel->center_freq, conf_is_ht(conf), conf_is_ht40(conf),
                fastcc);
-
-       if (!fastcc)
-               caldata = &priv->caldata;
-
+       caldata = fastcc ? NULL : &priv->caldata;
        ret = ath9k_hw_reset(ah, hchan, caldata, fastcc);
        if (ret) {
                ath_err(common,
index 4200906..8b2895f 100644 (file)
@@ -2914,8 +2914,7 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan,
 {
        struct ath_regulatory *reg = ath9k_hw_regulatory(ah);
        struct ieee80211_channel *channel;
-       int chan_pwr, new_pwr, max_gain;
-       int ant_gain, ant_reduction = 0;
+       int chan_pwr, new_pwr;
 
        if (!chan)
                return;
@@ -2923,15 +2922,10 @@ void ath9k_hw_apply_txpower(struct ath_hw *ah, struct ath9k_channel *chan,
        channel = chan->chan;
        chan_pwr = min_t(int, channel->max_power * 2, MAX_RATE_POWER);
        new_pwr = min_t(int, chan_pwr, reg->power_limit);
-       max_gain = chan_pwr - new_pwr + channel->max_antenna_gain * 2;
-
-       ant_gain = get_antenna_gain(ah, chan);
-       if (ant_gain > max_gain)
-               ant_reduction = ant_gain - max_gain;
 
        ah->eep_ops->set_txpower(ah, chan,
                                 ath9k_regd_get_ctl(reg, chan),
-                                ant_reduction, new_pwr, test);
+                                get_antenna_gain(ah, chan), new_pwr, test);
 }
 
 void ath9k_hw_set_txpowerlimit(struct ath_hw *ah, u32 limit, bool test)
index 4bf1e24..2ee8624 100644 (file)
@@ -49,6 +49,10 @@ int ath9k_led_blink;
 module_param_named(blink, ath9k_led_blink, int, 0444);
 MODULE_PARM_DESC(blink, "Enable LED blink on activity");
 
+static int ath9k_led_active_high = -1;
+module_param_named(led_active_high, ath9k_led_active_high, int, 0444);
+MODULE_PARM_DESC(led_active_high, "Invert LED polarity");
+
 static int ath9k_btcoex_enable;
 module_param_named(btcoex_enable, ath9k_btcoex_enable, int, 0444);
 MODULE_PARM_DESC(btcoex_enable, "Enable wifi-BT coexistence");
@@ -477,7 +481,7 @@ static void ath9k_eeprom_request_cb(const struct firmware *eeprom_blob,
 static int ath9k_eeprom_request(struct ath_softc *sc, const char *name)
 {
        struct ath9k_eeprom_ctx ec;
-       struct ath_hw *ah = ah = sc->sc_ah;
+       struct ath_hw *ah = sc->sc_ah;
        int err;
 
        /* try to load the EEPROM content asynchronously */
@@ -600,6 +604,9 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        if (ret)
                return ret;
 
+       if (ath9k_led_active_high != -1)
+               ah->config.led_active_high = ath9k_led_active_high == 1;
+
        /*
         * Enable WLAN/BT RX Antenna diversity only when:
         *
index e6fef1b..7cdaf40 100644 (file)
@@ -28,6 +28,16 @@ static const struct pci_device_id ath_pci_id_table[] = {
        { PCI_VDEVICE(ATHEROS, 0x0024) }, /* PCI-E */
        { PCI_VDEVICE(ATHEROS, 0x0027) }, /* PCI   */
        { PCI_VDEVICE(ATHEROS, 0x0029) }, /* PCI   */
+
+#ifdef CONFIG_ATH9K_PCOEM
+       /* Mini PCI AR9220 MB92 cards: Compex WLM200NX, Wistron DNMA-92 */
+       { PCI_DEVICE_SUB(PCI_VENDOR_ID_ATHEROS,
+                        0x0029,
+                        PCI_VENDOR_ID_ATHEROS,
+                        0x2096),
+         .driver_data = ATH9K_PCI_LED_ACT_HI },
+#endif
+
        { PCI_VDEVICE(ATHEROS, 0x002A) }, /* PCI-E */
 
 #ifdef CONFIG_ATH9K_PCOEM
index ef44a2d..2a6bb62 100644 (file)
@@ -33,9 +33,7 @@ static ssize_t read_file_bool_bmps(struct file *file, char __user *user_buf,
        char buf[3];
 
        list_for_each_entry(vif_priv, &wcn->vif_list, list) {
-                       vif = container_of((void *)vif_priv,
-                                  struct ieee80211_vif,
-                                  drv_priv);
+                       vif = wcn36xx_priv_to_vif(vif_priv);
                        if (NL80211_IFTYPE_STATION == vif->type) {
                                if (vif_priv->pw_state == WCN36XX_BMPS)
                                        buf[0] = '1';
@@ -70,9 +68,7 @@ static ssize_t write_file_bool_bmps(struct file *file,
        case 'Y':
        case '1':
                list_for_each_entry(vif_priv, &wcn->vif_list, list) {
-                       vif = container_of((void *)vif_priv,
-                                  struct ieee80211_vif,
-                                  drv_priv);
+                       vif = wcn36xx_priv_to_vif(vif_priv);
                        if (NL80211_IFTYPE_STATION == vif->type) {
                                wcn36xx_enable_keep_alive_null_packet(wcn, vif);
                                wcn36xx_pmc_enter_bmps_state(wcn, vif);
@@ -83,9 +79,7 @@ static ssize_t write_file_bool_bmps(struct file *file,
        case 'N':
        case '0':
                list_for_each_entry(vif_priv, &wcn->vif_list, list) {
-                       vif = container_of((void *)vif_priv,
-                                  struct ieee80211_vif,
-                                  drv_priv);
+                       vif = wcn36xx_priv_to_vif(vif_priv);
                        if (NL80211_IFTYPE_STATION == vif->type)
                                wcn36xx_pmc_exit_bmps_state(wcn, vif);
                }
index b947de0..658bfb8 100644 (file)
 
 #define WCN36XX_HAL_IPV4_ADDR_LEN       4
 
-#define WALN_HAL_STA_INVALID_IDX 0xFF
+#define WCN36XX_HAL_STA_INVALID_IDX 0xFF
 #define WCN36XX_HAL_BSS_INVALID_IDX 0xFF
 
 /* Default Beacon template size */
 #define BEACON_TEMPLATE_SIZE 0x180
 
+/* Minimum PVM size that the FW expects. See comment in smd.c for details. */
+#define TIM_MIN_PVM_SIZE 6
+
 /* Param Change Bitmap sent to HAL */
 #define PARAM_BCN_INTERVAL_CHANGED                      (1 << 0)
 #define PARAM_SHORT_PREAMBLE_CHANGED                 (1 << 1)
@@ -2884,11 +2887,14 @@ struct update_beacon_rsp_msg {
 struct wcn36xx_hal_send_beacon_req_msg {
        struct wcn36xx_hal_msg_header header;
 
+       /* length of the template + 6. Only qcom knows why */
+       u32 beacon_length6;
+
        /* length of the template. */
        u32 beacon_length;
 
        /* Beacon data. */
-       u8 beacon[BEACON_TEMPLATE_SIZE];
+       u8 beacon[BEACON_TEMPLATE_SIZE - sizeof(u32)];
 
        u8 bssid[ETH_ALEN];
 
@@ -4261,9 +4267,9 @@ struct wcn36xx_hal_rcv_flt_mc_addr_list_type {
        u8 data_offset;
 
        u32 mc_addr_count;
-       u8 mc_addr[ETH_ALEN][WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS];
+       u8 mc_addr[WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS][ETH_ALEN];
        u8 bss_index;
-};
+} __packed;
 
 struct wcn36xx_hal_set_pkt_filter_rsp_msg {
        struct wcn36xx_hal_msg_header header;
@@ -4317,7 +4323,7 @@ struct wcn36xx_hal_rcv_flt_pkt_clear_rsp_msg {
 struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg {
        struct wcn36xx_hal_msg_header header;
        struct wcn36xx_hal_rcv_flt_mc_addr_list_type mc_addr_list;
-};
+} __packed;
 
 struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_rsp_msg {
        struct wcn36xx_hal_msg_header header;
@@ -4383,6 +4389,45 @@ enum place_holder_in_cap_bitmap {
        RTT = 20,
        RATECTRL = 21,
        WOW = 22,
+       WLAN_ROAM_SCAN_OFFLOAD = 23,
+       SPECULATIVE_PS_POLL = 24,
+       SCAN_SCH = 25,
+       IBSS_HEARTBEAT_OFFLOAD = 26,
+       WLAN_SCAN_OFFLOAD = 27,
+       WLAN_PERIODIC_TX_PTRN = 28,
+       ADVANCE_TDLS = 29,
+       BATCH_SCAN = 30,
+       FW_IN_TX_PATH = 31,
+       EXTENDED_NSOFFLOAD_SLOT = 32,
+       CH_SWITCH_V1 = 33,
+       HT40_OBSS_SCAN = 34,
+       UPDATE_CHANNEL_LIST = 35,
+       WLAN_MCADDR_FLT = 36,
+       WLAN_CH144 = 37,
+       NAN = 38,
+       TDLS_SCAN_COEXISTENCE = 39,
+       LINK_LAYER_STATS_MEAS = 40,
+       MU_MIMO = 41,
+       EXTENDED_SCAN = 42,
+       DYNAMIC_WMM_PS = 43,
+       MAC_SPOOFED_SCAN = 44,
+       BMU_ERROR_GENERIC_RECOVERY = 45,
+       DISA = 46,
+       FW_STATS = 47,
+       WPS_PRBRSP_TMPL = 48,
+       BCN_IE_FLT_DELTA = 49,
+       TDLS_OFF_CHANNEL = 51,
+       RTT3 = 52,
+       MGMT_FRAME_LOGGING = 53,
+       ENHANCED_TXBD_COMPLETION = 54,
+       LOGGING_ENHANCEMENT = 55,
+       EXT_SCAN_ENHANCED = 56,
+       MEMORY_DUMP_SUPPORTED = 57,
+       PER_PKT_STATS_SUPPORTED = 58,
+       EXT_LL_STAT = 60,
+       WIFI_CONFIG = 61,
+       ANTENNA_DIVERSITY_SELECTION = 62,
+
        MAX_FEATURE_SUPPORTED = 128,
 };
 
index 9a1db3b..a920d70 100644 (file)
@@ -201,7 +201,45 @@ static const char * const wcn36xx_caps_names[] = {
        "BCN_FILTER",                   /* 19 */
        "RTT",                          /* 20 */
        "RATECTRL",                     /* 21 */
-       "WOW"                           /* 22 */
+       "WOW",                          /* 22 */
+       "WLAN_ROAM_SCAN_OFFLOAD",       /* 23 */
+       "SPECULATIVE_PS_POLL",          /* 24 */
+       "SCAN_SCH",                     /* 25 */
+       "IBSS_HEARTBEAT_OFFLOAD",       /* 26 */
+       "WLAN_SCAN_OFFLOAD",            /* 27 */
+       "WLAN_PERIODIC_TX_PTRN",        /* 28 */
+       "ADVANCE_TDLS",                 /* 29 */
+       "BATCH_SCAN",                   /* 30 */
+       "FW_IN_TX_PATH",                /* 31 */
+       "EXTENDED_NSOFFLOAD_SLOT",      /* 32 */
+       "CH_SWITCH_V1",                 /* 33 */
+       "HT40_OBSS_SCAN",               /* 34 */
+       "UPDATE_CHANNEL_LIST",          /* 35 */
+       "WLAN_MCADDR_FLT",              /* 36 */
+       "WLAN_CH144",                   /* 37 */
+       "NAN",                          /* 38 */
+       "TDLS_SCAN_COEXISTENCE",        /* 39 */
+       "LINK_LAYER_STATS_MEAS",        /* 40 */
+       "MU_MIMO",                      /* 41 */
+       "EXTENDED_SCAN",                /* 42 */
+       "DYNAMIC_WMM_PS",               /* 43 */
+       "MAC_SPOOFED_SCAN",             /* 44 */
+       "BMU_ERROR_GENERIC_RECOVERY",   /* 45 */
+       "DISA",                         /* 46 */
+       "FW_STATS",                     /* 47 */
+       "WPS_PRBRSP_TMPL",              /* 48 */
+       "BCN_IE_FLT_DELTA",             /* 49 */
+       "TDLS_OFF_CHANNEL",             /* 51 */
+       "RTT3",                         /* 52 */
+       "MGMT_FRAME_LOGGING",           /* 53 */
+       "ENHANCED_TXBD_COMPLETION",     /* 54 */
+       "LOGGING_ENHANCEMENT",          /* 55 */
+       "EXT_SCAN_ENHANCED",            /* 56 */
+       "MEMORY_DUMP_SUPPORTED",        /* 57 */
+       "PER_PKT_STATS_SUPPORTED",      /* 58 */
+       "EXT_LL_STAT",                  /* 60 */
+       "WIFI_CONFIG",                  /* 61 */
+       "ANTENNA_DIVERSITY_SELECTION",  /* 62 */
 };
 
 static const char *wcn36xx_get_cap_name(enum place_holder_in_cap_bitmap x)
@@ -287,6 +325,7 @@ static int wcn36xx_start(struct ieee80211_hw *hw)
        }
 
        wcn36xx_detect_chip_version(wcn);
+       wcn36xx_smd_update_cfg(wcn, WCN36XX_HAL_CFG_ENABLE_MC_ADDR_LIST, 1);
 
        /* DMA channel initialization */
        ret = wcn36xx_dxe_init(wcn);
@@ -346,9 +385,7 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
                wcn36xx_dbg(WCN36XX_DBG_MAC, "wcn36xx_config channel switch=%d\n",
                            ch);
                list_for_each_entry(tmp, &wcn->vif_list, list) {
-                       vif = container_of((void *)tmp,
-                                          struct ieee80211_vif,
-                                          drv_priv);
+                       vif = wcn36xx_priv_to_vif(tmp);
                        wcn36xx_smd_switch_channel(wcn, vif, ch);
                }
        }
@@ -356,15 +393,57 @@ static int wcn36xx_config(struct ieee80211_hw *hw, u32 changed)
        return 0;
 }
 
-#define WCN36XX_SUPPORTED_FILTERS (0)
-
 static void wcn36xx_configure_filter(struct ieee80211_hw *hw,
                                     unsigned int changed,
                                     unsigned int *total, u64 multicast)
 {
+       struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
+       struct wcn36xx *wcn = hw->priv;
+       struct wcn36xx_vif *tmp;
+       struct ieee80211_vif *vif = NULL;
+
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac configure filter\n");
 
-       *total &= WCN36XX_SUPPORTED_FILTERS;
+       *total &= FIF_ALLMULTI;
+
+       fp = (void *)(unsigned long)multicast;
+       list_for_each_entry(tmp, &wcn->vif_list, list) {
+               vif = wcn36xx_priv_to_vif(tmp);
+
+               /* FW handles MC filtering only when connected as STA */
+               if (*total & FIF_ALLMULTI)
+                       wcn36xx_smd_set_mc_list(wcn, vif, NULL);
+               else if (NL80211_IFTYPE_STATION == vif->type && tmp->sta_assoc)
+                       wcn36xx_smd_set_mc_list(wcn, vif, fp);
+       }
+       kfree(fp);
+}
+
+static u64 wcn36xx_prepare_multicast(struct ieee80211_hw *hw,
+                                    struct netdev_hw_addr_list *mc_list)
+{
+       struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp;
+       struct netdev_hw_addr *ha;
+
+       wcn36xx_dbg(WCN36XX_DBG_MAC, "mac prepare multicast list\n");
+       fp = kzalloc(sizeof(*fp), GFP_ATOMIC);
+       if (!fp) {
+               wcn36xx_err("Out of memory setting filters.\n");
+               return 0;
+       }
+
+       fp->mc_addr_count = 0;
+       /* update multicast filtering parameters */
+       if (netdev_hw_addr_list_count(mc_list) <=
+           WCN36XX_HAL_MAX_NUM_MULTICAST_ADDRESS) {
+               netdev_hw_addr_list_for_each(ha, mc_list) {
+                       memcpy(fp->mc_addr[fp->mc_addr_count],
+                                       ha->addr, ETH_ALEN);
+                       fp->mc_addr_count++;
+               }
+       }
+
+       return (u64)(unsigned long)fp;
 }
 
 static void wcn36xx_tx(struct ieee80211_hw *hw,
@@ -375,7 +454,7 @@ static void wcn36xx_tx(struct ieee80211_hw *hw,
        struct wcn36xx_sta *sta_priv = NULL;
 
        if (control->sta)
-               sta_priv = (struct wcn36xx_sta *)control->sta->drv_priv;
+               sta_priv = wcn36xx_sta_to_priv(control->sta);
 
        if (wcn36xx_start_tx(wcn, sta_priv, skb))
                ieee80211_free_txskb(wcn->hw, skb);
@@ -387,8 +466,8 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                           struct ieee80211_key_conf *key_conf)
 {
        struct wcn36xx *wcn = hw->priv;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
-       struct wcn36xx_sta *sta_priv = vif_priv->sta;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+       struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
        int ret = 0;
        u8 key[WLAN_MAX_KEY_LEN];
 
@@ -473,6 +552,7 @@ static int wcn36xx_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                break;
        case DISABLE_KEY:
                if (!(IEEE80211_KEY_FLAG_PAIRWISE & key_conf->flags)) {
+                       vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;
                        wcn36xx_smd_remove_bsskey(wcn,
                                vif_priv->encrypt_type,
                                key_conf->keyidx);
@@ -520,7 +600,7 @@ static void wcn36xx_update_allowed_rates(struct ieee80211_sta *sta,
 {
        int i, size;
        u16 *rates_table;
-       struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+       struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
        u32 rates = sta->supp_rates[band];
 
        memset(&sta_priv->supported_rates, 0,
@@ -590,7 +670,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
        struct sk_buff *skb = NULL;
        u16 tim_off, tim_len;
        enum wcn36xx_hal_link_state link_state;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac bss info changed vif %p changed 0x%08x\n",
                    vif, changed);
@@ -620,7 +700,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
 
                if (!is_zero_ether_addr(bss_conf->bssid)) {
                        vif_priv->is_joining = true;
-                       vif_priv->bss_index = 0xff;
+                       vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;
                        wcn36xx_smd_join(wcn, bss_conf->bssid,
                                         vif->addr, WCN36XX_HW_CHANNEL(wcn));
                        wcn36xx_smd_config_bss(wcn, vif, NULL,
@@ -628,6 +708,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
                } else {
                        vif_priv->is_joining = false;
                        wcn36xx_smd_delete_bss(wcn, vif);
+                       vif_priv->encrypt_type = WCN36XX_HAL_ED_NONE;
                }
        }
 
@@ -655,6 +736,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
                                     vif->addr,
                                     bss_conf->aid);
 
+                       vif_priv->sta_assoc = true;
                        rcu_read_lock();
                        sta = ieee80211_find_sta(vif, bss_conf->bssid);
                        if (!sta) {
@@ -663,7 +745,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
                                rcu_read_unlock();
                                goto out;
                        }
-                       sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+                       sta_priv = wcn36xx_sta_to_priv(sta);
 
                        wcn36xx_update_allowed_rates(sta, WCN36XX_BAND(wcn));
 
@@ -686,6 +768,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
                                    bss_conf->bssid,
                                    vif->addr,
                                    bss_conf->aid);
+                       vif_priv->sta_assoc = false;
                        wcn36xx_smd_set_link_st(wcn,
                                                bss_conf->bssid,
                                                vif->addr,
@@ -713,7 +796,7 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
 
                if (bss_conf->enable_beacon) {
                        vif_priv->dtim_period = bss_conf->dtim_period;
-                       vif_priv->bss_index = 0xff;
+                       vif_priv->bss_index = WCN36XX_HAL_BSS_INVALID_IDX;
                        wcn36xx_smd_config_bss(wcn, vif, NULL,
                                               vif->addr, false);
                        skb = ieee80211_beacon_get_tim(hw, vif, &tim_off,
@@ -734,9 +817,9 @@ static void wcn36xx_bss_info_changed(struct ieee80211_hw *hw,
                        wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
                                                link_state);
                } else {
+                       wcn36xx_smd_delete_bss(wcn, vif);
                        wcn36xx_smd_set_link_st(wcn, vif->addr, vif->addr,
                                                WCN36XX_HAL_LINK_IDLE_STATE);
-                       wcn36xx_smd_delete_bss(wcn, vif);
                }
        }
 out:
@@ -757,7 +840,7 @@ static void wcn36xx_remove_interface(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif)
 {
        struct wcn36xx *wcn = hw->priv;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac remove interface vif %p\n", vif);
 
        list_del(&vif_priv->list);
@@ -768,7 +851,7 @@ static int wcn36xx_add_interface(struct ieee80211_hw *hw,
                                 struct ieee80211_vif *vif)
 {
        struct wcn36xx *wcn = hw->priv;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac add interface vif %p type %d\n",
                    vif, vif->type);
@@ -792,13 +875,12 @@ static int wcn36xx_sta_add(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                           struct ieee80211_sta *sta)
 {
        struct wcn36xx *wcn = hw->priv;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
-       struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+       struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta add vif %p sta %pM\n",
                    vif, sta->addr);
 
        spin_lock_init(&sta_priv->ampdu_lock);
-       vif_priv->sta = sta_priv;
        sta_priv->vif = vif_priv;
        /*
         * For STA mode HW will be configured on BSS_CHANGED_ASSOC because
@@ -817,14 +899,12 @@ static int wcn36xx_sta_remove(struct ieee80211_hw *hw,
                              struct ieee80211_sta *sta)
 {
        struct wcn36xx *wcn = hw->priv;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
-       struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+       struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
 
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac sta remove vif %p sta %pM index %d\n",
                    vif, sta->addr, sta_priv->sta_index);
 
        wcn36xx_smd_delete_sta(wcn, sta_priv->sta_index);
-       vif_priv->sta = NULL;
        sta_priv->vif = NULL;
        return 0;
 }
@@ -860,7 +940,7 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
                    struct ieee80211_ampdu_params *params)
 {
        struct wcn36xx *wcn = hw->priv;
-       struct wcn36xx_sta *sta_priv = NULL;
+       struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(params->sta);
        struct ieee80211_sta *sta = params->sta;
        enum ieee80211_ampdu_mlme_action action = params->action;
        u16 tid = params->tid;
@@ -869,8 +949,6 @@ static int wcn36xx_ampdu_action(struct ieee80211_hw *hw,
        wcn36xx_dbg(WCN36XX_DBG_MAC, "mac ampdu action action %d tid %d\n",
                    action, tid);
 
-       sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
-
        switch (action) {
        case IEEE80211_AMPDU_RX_START:
                sta_priv->tid = tid;
@@ -923,6 +1001,7 @@ static const struct ieee80211_ops wcn36xx_ops = {
        .resume                 = wcn36xx_resume,
 #endif
        .config                 = wcn36xx_config,
+       .prepare_multicast      = wcn36xx_prepare_multicast,
        .configure_filter       = wcn36xx_configure_filter,
        .tx                     = wcn36xx_tx,
        .set_key                = wcn36xx_set_key,
index 28b515c..589fe5f 100644 (file)
@@ -22,7 +22,7 @@ int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn,
                                 struct ieee80211_vif *vif)
 {
        int ret = 0;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
        /* TODO: Make sure the TX chain clean */
        ret = wcn36xx_smd_enter_bmps(wcn, vif);
        if (!ret) {
@@ -42,7 +42,7 @@ int wcn36xx_pmc_enter_bmps_state(struct wcn36xx *wcn,
 int wcn36xx_pmc_exit_bmps_state(struct wcn36xx *wcn,
                                struct ieee80211_vif *vif)
 {
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 
        if (WCN36XX_BMPS != vif_priv->pw_state) {
                wcn36xx_err("Not in BMPS mode, no need to exit from BMPS mode!\n");
index 96992a2..e8b630c 100644 (file)
@@ -191,16 +191,16 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
                struct ieee80211_sta *sta,
                struct wcn36xx_hal_config_sta_params *sta_params)
 {
-       struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv;
-       struct wcn36xx_sta *priv_sta = NULL;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+       struct wcn36xx_sta *sta_priv = NULL;
        if (vif->type == NL80211_IFTYPE_ADHOC ||
            vif->type == NL80211_IFTYPE_AP ||
            vif->type == NL80211_IFTYPE_MESH_POINT) {
                sta_params->type = 1;
-               sta_params->sta_index = 0xFF;
+               sta_params->sta_index = WCN36XX_HAL_STA_INVALID_IDX;
        } else {
                sta_params->type = 0;
-               sta_params->sta_index = 1;
+               sta_params->sta_index = vif_priv->self_sta_index;
        }
 
        sta_params->listen_interval = WCN36XX_LISTEN_INTERVAL(wcn);
@@ -215,7 +215,7 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
        else
                memcpy(&sta_params->bssid, vif->addr, ETH_ALEN);
 
-       sta_params->encrypt_type = priv_vif->encrypt_type;
+       sta_params->encrypt_type = vif_priv->encrypt_type;
        sta_params->short_preamble_supported = true;
 
        sta_params->rifs_mode = 0;
@@ -224,21 +224,21 @@ static void wcn36xx_smd_set_sta_params(struct wcn36xx *wcn,
        sta_params->uapsd = 0;
        sta_params->mimo_ps = WCN36XX_HAL_HT_MIMO_PS_STATIC;
        sta_params->max_ampdu_duration = 0;
-       sta_params->bssid_index = priv_vif->bss_index;
+       sta_params->bssid_index = vif_priv->bss_index;
        sta_params->p2p = 0;
 
        if (sta) {
-               priv_sta = (struct wcn36xx_sta *)sta->drv_priv;
+               sta_priv = wcn36xx_sta_to_priv(sta);
                if (NL80211_IFTYPE_STATION == vif->type)
                        memcpy(&sta_params->bssid, sta->addr, ETH_ALEN);
                else
                        memcpy(&sta_params->mac, sta->addr, ETH_ALEN);
                sta_params->wmm_enabled = sta->wme;
                sta_params->max_sp_len = sta->max_sp;
-               sta_params->aid = priv_sta->aid;
+               sta_params->aid = sta_priv->aid;
                wcn36xx_smd_set_sta_ht_params(sta, sta_params);
-               memcpy(&sta_params->supported_rates, &priv_sta->supported_rates,
-                       sizeof(priv_sta->supported_rates));
+               memcpy(&sta_params->supported_rates, &sta_priv->supported_rates,
+                       sizeof(sta_priv->supported_rates));
        } else {
                wcn36xx_set_default_rates(&sta_params->supported_rates);
                wcn36xx_smd_set_sta_default_ht_params(sta_params);
@@ -271,6 +271,16 @@ out:
        return ret;
 }
 
+static void init_hal_msg(struct wcn36xx_hal_msg_header *hdr,
+                        enum wcn36xx_hal_host_msg_type msg_type,
+                        size_t msg_size)
+{
+       memset(hdr, 0, msg_size + sizeof(*hdr));
+       hdr->msg_type = msg_type;
+       hdr->msg_version = WCN36XX_HAL_MSG_VERSION0;
+       hdr->len = msg_size + sizeof(*hdr);
+}
+
 #define INIT_HAL_MSG(msg_body, type) \
        do {                                                            \
                memset(&msg_body, 0, sizeof(msg_body));                 \
@@ -302,22 +312,6 @@ static int wcn36xx_smd_rsp_status_check(void *buf, size_t len)
        return 0;
 }
 
-static int wcn36xx_smd_rsp_status_check_v2(struct wcn36xx *wcn, void *buf,
-                                            size_t len)
-{
-       struct wcn36xx_fw_msg_status_rsp_v2 *rsp;
-
-       if (len < sizeof(struct wcn36xx_hal_msg_header) + sizeof(*rsp))
-               return wcn36xx_smd_rsp_status_check(buf, len);
-
-       rsp = buf + sizeof(struct wcn36xx_hal_msg_header);
-
-       if (WCN36XX_FW_MSG_RESULT_SUCCESS != rsp->status)
-               return rsp->status;
-
-       return 0;
-}
-
 int wcn36xx_smd_load_nv(struct wcn36xx *wcn)
 {
        struct nv_data *nv_d;
@@ -726,7 +720,7 @@ static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn,
                                        size_t len)
 {
        struct wcn36xx_hal_add_sta_self_rsp_msg *rsp;
-       struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 
        if (len < sizeof(*rsp))
                return -EINVAL;
@@ -743,8 +737,8 @@ static int wcn36xx_smd_add_sta_self_rsp(struct wcn36xx *wcn,
                    "hal add sta self status %d self_sta_index %d dpu_index %d\n",
                    rsp->status, rsp->self_sta_index, rsp->dpu_index);
 
-       priv_vif->self_sta_index = rsp->self_sta_index;
-       priv_vif->self_dpu_desc_index = rsp->dpu_index;
+       vif_priv->self_sta_index = rsp->self_sta_index;
+       vif_priv->self_dpu_desc_index = rsp->dpu_index;
 
        return 0;
 }
@@ -949,17 +943,32 @@ static void wcn36xx_smd_convert_sta_to_v1(struct wcn36xx *wcn,
        memcpy(&v1->mac, orig->mac, ETH_ALEN);
        v1->aid = orig->aid;
        v1->type = orig->type;
+       v1->short_preamble_supported = orig->short_preamble_supported;
        v1->listen_interval = orig->listen_interval;
+       v1->wmm_enabled = orig->wmm_enabled;
        v1->ht_capable = orig->ht_capable;
-
+       v1->tx_channel_width_set = orig->tx_channel_width_set;
+       v1->rifs_mode = orig->rifs_mode;
+       v1->lsig_txop_protection = orig->lsig_txop_protection;
        v1->max_ampdu_size = orig->max_ampdu_size;
        v1->max_ampdu_density = orig->max_ampdu_density;
        v1->sgi_40mhz = orig->sgi_40mhz;
        v1->sgi_20Mhz = orig->sgi_20Mhz;
-
+       v1->rmf = orig->rmf;
+       v1->encrypt_type = orig->encrypt_type;
+       v1->action = orig->action;
+       v1->uapsd = orig->uapsd;
+       v1->max_sp_len = orig->max_sp_len;
+       v1->green_field_capable = orig->green_field_capable;
+       v1->mimo_ps = orig->mimo_ps;
+       v1->delayed_ba_support = orig->delayed_ba_support;
+       v1->max_ampdu_duration = orig->max_ampdu_duration;
+       v1->dsss_cck_mode_40mhz = orig->dsss_cck_mode_40mhz;
        memcpy(&v1->supported_rates, &orig->supported_rates,
               sizeof(orig->supported_rates));
        v1->sta_index = orig->sta_index;
+       v1->bssid_index = orig->bssid_index;
+       v1->p2p = orig->p2p;
 }
 
 static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
@@ -969,7 +978,7 @@ static int wcn36xx_smd_config_sta_rsp(struct wcn36xx *wcn,
 {
        struct wcn36xx_hal_config_sta_rsp_msg *rsp;
        struct config_sta_rsp_params *params;
-       struct wcn36xx_sta *sta_priv = (struct wcn36xx_sta *)sta->drv_priv;
+       struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
 
        if (len < sizeof(*rsp))
                return -EINVAL;
@@ -1170,12 +1179,13 @@ static int wcn36xx_smd_config_bss_v1(struct wcn36xx *wcn,
 
 static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn,
                                      struct ieee80211_vif *vif,
+                                     struct ieee80211_sta *sta,
                                      void *buf,
                                      size_t len)
 {
        struct wcn36xx_hal_config_bss_rsp_msg *rsp;
        struct wcn36xx_hal_config_bss_rsp_params *params;
-       struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
 
        if (len < sizeof(*rsp))
                return -EINVAL;
@@ -1198,14 +1208,15 @@ static int wcn36xx_smd_config_bss_rsp(struct wcn36xx *wcn,
                    params->bss_bcast_sta_idx, params->mac,
                    params->tx_mgmt_power, params->ucast_dpu_signature);
 
-       priv_vif->bss_index = params->bss_index;
+       vif_priv->bss_index = params->bss_index;
 
-       if (priv_vif->sta) {
-               priv_vif->sta->bss_sta_index =  params->bss_sta_index;
-               priv_vif->sta->bss_dpu_desc_index = params->dpu_desc_index;
+       if (sta) {
+               struct wcn36xx_sta *sta_priv = wcn36xx_sta_to_priv(sta);
+               sta_priv->bss_sta_index = params->bss_sta_index;
+               sta_priv->bss_dpu_desc_index = params->dpu_desc_index;
        }
 
-       priv_vif->self_ucast_dpu_sign = params->ucast_dpu_signature;
+       vif_priv->self_ucast_dpu_sign = params->ucast_dpu_signature;
 
        return 0;
 }
@@ -1217,7 +1228,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
        struct wcn36xx_hal_config_bss_req_msg msg;
        struct wcn36xx_hal_config_bss_params *bss;
        struct wcn36xx_hal_config_sta_params *sta_params;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
        int ret = 0;
 
        mutex_lock(&wcn->hal_mutex);
@@ -1329,6 +1340,7 @@ int wcn36xx_smd_config_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif,
        }
        ret = wcn36xx_smd_config_bss_rsp(wcn,
                                         vif,
+                                        sta,
                                         wcn->hal_buf,
                                         wcn->hal_rsp_len);
        if (ret) {
@@ -1343,13 +1355,13 @@ out:
 int wcn36xx_smd_delete_bss(struct wcn36xx *wcn, struct ieee80211_vif *vif)
 {
        struct wcn36xx_hal_delete_bss_req_msg msg_body;
-       struct wcn36xx_vif *priv_vif = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
        int ret = 0;
 
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_DELETE_BSS_REQ);
 
-       msg_body.bss_index = priv_vif->bss_index;
+       msg_body.bss_index = vif_priv->bss_index;
 
        PREPARE_HAL_BUF(wcn->hal_buf, msg_body);
 
@@ -1375,26 +1387,47 @@ int wcn36xx_smd_send_beacon(struct wcn36xx *wcn, struct ieee80211_vif *vif,
                            u16 p2p_off)
 {
        struct wcn36xx_hal_send_beacon_req_msg msg_body;
-       int ret = 0;
+       int ret = 0, pad, pvm_len;
 
        mutex_lock(&wcn->hal_mutex);
        INIT_HAL_MSG(msg_body, WCN36XX_HAL_SEND_BEACON_REQ);
 
-       /* TODO need to find out why this is needed? */
-       msg_body.beacon_length = skb_beacon->len + 6;
+       pvm_len = skb_beacon->data[tim_off + 1] - 3;
+       pad = TIM_MIN_PVM_SIZE - pvm_len;
 
-       if (BEACON_TEMPLATE_SIZE > msg_body.beacon_length) {
-               memcpy(&msg_body.beacon, &skb_beacon->len, sizeof(u32));
-               memcpy(&(msg_body.beacon[4]), skb_beacon->data,
-                      skb_beacon->len);
-       } else {
+       /* Padding is irrelevant to mesh mode since tim_off is always 0. */
+       if (vif->type == NL80211_IFTYPE_MESH_POINT)
+               pad = 0;
+
+       msg_body.beacon_length = skb_beacon->len + pad;
+       /* TODO need to find out why + 6 is needed */
+       msg_body.beacon_length6 = msg_body.beacon_length + 6;
+
+       if (msg_body.beacon_length > BEACON_TEMPLATE_SIZE) {
                wcn36xx_err("Beacon is to big: beacon size=%d\n",
                              msg_body.beacon_length);
                ret = -ENOMEM;
                goto out;
        }
+       memcpy(msg_body.beacon, skb_beacon->data, skb_beacon->len);
        memcpy(msg_body.bssid, vif->addr, ETH_ALEN);
 
+       if (pad > 0) {
+               /*
+                * The wcn36xx FW has a fixed size for the PVM in the TIM. If
+                * given the beacon template from mac80211 with a PVM shorter
+                * than the FW expectes it will overwrite the data after the
+                * TIM.
+                */
+               wcn36xx_dbg(WCN36XX_DBG_HAL, "Pad TIM PVM. %d bytes at %d\n",
+                           pad, pvm_len);
+               memmove(&msg_body.beacon[tim_off + 5 + pvm_len + pad],
+                       &msg_body.beacon[tim_off + 5 + pvm_len],
+                       skb_beacon->len - (tim_off + 5 + pvm_len));
+               memset(&msg_body.beacon[tim_off + 5 + pvm_len], 0, pad);
+               msg_body.beacon[tim_off + 1] += pad;
+       }
+
        /* TODO need to find out why this is needed? */
        if (vif->type == NL80211_IFTYPE_MESH_POINT)
                /* mesh beacon don't need this, so push further down */
@@ -1598,8 +1631,7 @@ int wcn36xx_smd_remove_bsskey(struct wcn36xx *wcn,
                wcn36xx_err("Sending hal_remove_bsskey failed\n");
                goto out;
        }
-       ret = wcn36xx_smd_rsp_status_check_v2(wcn, wcn->hal_buf,
-                                             wcn->hal_rsp_len);
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
        if (ret) {
                wcn36xx_err("hal_remove_bsskey response failed err=%d\n", ret);
                goto out;
@@ -1612,7 +1644,7 @@ out:
 int wcn36xx_smd_enter_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif)
 {
        struct wcn36xx_hal_enter_bmps_req_msg msg_body;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
        int ret = 0;
 
        mutex_lock(&wcn->hal_mutex);
@@ -1641,8 +1673,8 @@ out:
 
 int wcn36xx_smd_exit_bmps(struct wcn36xx *wcn, struct ieee80211_vif *vif)
 {
-       struct wcn36xx_hal_enter_bmps_req_msg msg_body;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_hal_exit_bmps_req_msg msg_body;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
        int ret = 0;
 
        mutex_lock(&wcn->hal_mutex);
@@ -1703,7 +1735,7 @@ int wcn36xx_smd_keep_alive_req(struct wcn36xx *wcn,
                               int packet_type)
 {
        struct wcn36xx_hal_keep_alive_req_msg msg_body;
-       struct wcn36xx_vif *vif_priv = (struct wcn36xx_vif *)vif->drv_priv;
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
        int ret = 0;
 
        mutex_lock(&wcn->hal_mutex);
@@ -1944,6 +1976,17 @@ out:
        return ret;
 }
 
+static int wcn36xx_smd_trigger_ba_rsp(void *buf, int len)
+{
+       struct wcn36xx_hal_trigger_ba_rsp_msg *rsp;
+
+       if (len < sizeof(*rsp))
+               return -EINVAL;
+
+       rsp = (struct wcn36xx_hal_trigger_ba_rsp_msg *) buf;
+       return rsp->status;
+}
+
 int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
 {
        struct wcn36xx_hal_trigger_ba_req_msg msg_body;
@@ -1968,8 +2011,7 @@ int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index)
                wcn36xx_err("Sending hal_trigger_ba failed\n");
                goto out;
        }
-       ret = wcn36xx_smd_rsp_status_check_v2(wcn, wcn->hal_buf,
-                                               wcn->hal_rsp_len);
+       ret = wcn36xx_smd_trigger_ba_rsp(wcn->hal_buf, wcn->hal_rsp_len);
        if (ret) {
                wcn36xx_err("hal_trigger_ba response failed err=%d\n", ret);
                goto out;
@@ -2006,9 +2048,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn,
                list_for_each_entry(tmp, &wcn->vif_list, list) {
                        wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",
                                    tmp->bss_index);
-                       vif = container_of((void *)tmp,
-                                                struct ieee80211_vif,
-                                                drv_priv);
+                       vif = wcn36xx_priv_to_vif(tmp);
                        ieee80211_connection_loss(vif);
                }
                return 0;
@@ -2023,9 +2063,7 @@ static int wcn36xx_smd_missed_beacon_ind(struct wcn36xx *wcn,
                if (tmp->bss_index == rsp->bss_index) {
                        wcn36xx_dbg(WCN36XX_DBG_HAL, "beacon missed bss_index %d\n",
                                    rsp->bss_index);
-                       vif = container_of((void *)tmp,
-                                                struct ieee80211_vif,
-                                                drv_priv);
+                       vif = wcn36xx_priv_to_vif(tmp);
                        ieee80211_connection_loss(vif);
                        return 0;
                }
@@ -2041,25 +2079,24 @@ static int wcn36xx_smd_delete_sta_context_ind(struct wcn36xx *wcn,
 {
        struct wcn36xx_hal_delete_sta_context_ind_msg *rsp = buf;
        struct wcn36xx_vif *tmp;
-       struct ieee80211_sta *sta = NULL;
+       struct ieee80211_sta *sta;
 
        if (len != sizeof(*rsp)) {
                wcn36xx_warn("Corrupted delete sta indication\n");
                return -EIO;
        }
 
+       wcn36xx_dbg(WCN36XX_DBG_HAL, "delete station indication %pM index %d\n",
+                   rsp->addr2, rsp->sta_id);
+
        list_for_each_entry(tmp, &wcn->vif_list, list) {
-               if (sta && (tmp->sta->sta_index == rsp->sta_id)) {
-                       sta = container_of((void *)tmp->sta,
-                                                struct ieee80211_sta,
-                                                drv_priv);
-                       wcn36xx_dbg(WCN36XX_DBG_HAL,
-                                   "delete station indication %pM index %d\n",
-                                   rsp->addr2,
-                                   rsp->sta_id);
+               rcu_read_lock();
+               sta = ieee80211_find_sta(wcn36xx_priv_to_vif(tmp), rsp->addr2);
+               if (sta)
                        ieee80211_report_low_ack(sta, 0);
+               rcu_read_unlock();
+               if (sta)
                        return 0;
-               }
        }
 
        wcn36xx_warn("STA with addr %pM and index %d not found\n",
@@ -2100,6 +2137,46 @@ out:
        mutex_unlock(&wcn->hal_mutex);
        return ret;
 }
+
+int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
+                           struct ieee80211_vif *vif,
+                           struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp)
+{
+       struct wcn36xx_vif *vif_priv = wcn36xx_vif_to_priv(vif);
+       struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *msg_body = NULL;
+       int ret = 0;
+
+       mutex_lock(&wcn->hal_mutex);
+
+       msg_body = (struct wcn36xx_hal_rcv_flt_pkt_set_mc_list_req_msg *)
+                  wcn->hal_buf;
+       init_hal_msg(&msg_body->header, WCN36XX_HAL_8023_MULTICAST_LIST_REQ,
+                    sizeof(msg_body->mc_addr_list));
+
+       /* An empty list means all mc traffic will be received */
+       if (fp)
+               memcpy(&msg_body->mc_addr_list, fp,
+                      sizeof(msg_body->mc_addr_list));
+       else
+               msg_body->mc_addr_list.mc_addr_count = 0;
+
+       msg_body->mc_addr_list.bss_index = vif_priv->bss_index;
+
+       ret = wcn36xx_smd_send_and_wait(wcn, msg_body->header.len);
+       if (ret) {
+               wcn36xx_err("Sending HAL_8023_MULTICAST_LIST failed\n");
+               goto out;
+       }
+       ret = wcn36xx_smd_rsp_status_check(wcn->hal_buf, wcn->hal_rsp_len);
+       if (ret) {
+               wcn36xx_err("HAL_8023_MULTICAST_LIST rsp failed err=%d\n", ret);
+               goto out;
+       }
+out:
+       mutex_unlock(&wcn->hal_mutex);
+       return ret;
+}
+
 static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
 {
        struct wcn36xx_hal_msg_header *msg_header = buf;
@@ -2141,6 +2218,7 @@ static void wcn36xx_smd_rsp_process(struct wcn36xx *wcn, void *buf, size_t len)
        case WCN36XX_HAL_UPDATE_SCAN_PARAM_RSP:
        case WCN36XX_HAL_CH_SWITCH_RSP:
        case WCN36XX_HAL_FEATURE_CAPS_EXCHANGE_RSP:
+       case WCN36XX_HAL_8023_MULTICAST_LIST_RSP:
                memcpy(wcn->hal_buf, buf, len);
                wcn->hal_rsp_len = len;
                complete(&wcn->hal_rsp_compl);
index 8361f9e..d74d781 100644 (file)
@@ -44,15 +44,6 @@ struct wcn36xx_fw_msg_status_rsp {
        u32     status;
 } __packed;
 
-/* wcn3620 returns this for tigger_ba */
-
-struct wcn36xx_fw_msg_status_rsp_v2 {
-       u8      bss_id[6];
-       u32     status __packed;
-       u16     count_following_candidates __packed;
-       /* candidate list follows */
-};
-
 struct wcn36xx_hal_ind_msg {
        struct list_head list;
        u8 *msg;
@@ -136,4 +127,7 @@ int wcn36xx_smd_del_ba(struct wcn36xx *wcn, u16 tid, u8 sta_index);
 int wcn36xx_smd_trigger_ba(struct wcn36xx *wcn, u8 sta_index);
 
 int wcn36xx_smd_update_cfg(struct wcn36xx *wcn, u32 cfg_id, u32 value);
+int wcn36xx_smd_set_mc_list(struct wcn36xx *wcn,
+                           struct ieee80211_vif *vif,
+                           struct wcn36xx_hal_rcv_flt_mc_addr_list_type *fp);
 #endif /* _SMD_H_ */
index 6c47a73..1f34c2e 100644 (file)
@@ -102,9 +102,7 @@ static inline struct wcn36xx_vif *get_vif_by_addr(struct wcn36xx *wcn,
        struct wcn36xx_vif *vif_priv = NULL;
        struct ieee80211_vif *vif = NULL;
        list_for_each_entry(vif_priv, &wcn->vif_list, list) {
-                       vif = container_of((void *)vif_priv,
-                                  struct ieee80211_vif,
-                                  drv_priv);
+                       vif = wcn36xx_priv_to_vif(vif_priv);
                        if (memcmp(vif->addr, addr, ETH_ALEN) == 0)
                                return vif_priv;
        }
@@ -167,9 +165,7 @@ static void wcn36xx_set_tx_data(struct wcn36xx_tx_bd *bd,
         */
        if (sta_priv) {
                __vif_priv = sta_priv->vif;
-               vif = container_of((void *)__vif_priv,
-                                  struct ieee80211_vif,
-                                  drv_priv);
+               vif = wcn36xx_priv_to_vif(__vif_priv);
 
                bd->dpu_sign = sta_priv->ucast_dpu_sign;
                if (vif->type == NL80211_IFTYPE_STATION) {
index 7b41e83..7433d67 100644 (file)
@@ -125,10 +125,10 @@ struct wcn36xx_platform_ctrl_ops {
  */
 struct wcn36xx_vif {
        struct list_head list;
-       struct wcn36xx_sta *sta;
        u8 dtim_period;
        enum ani_ed_type encrypt_type;
        bool is_joining;
+       bool sta_assoc;
        struct wcn36xx_hal_mac_ssid ssid;
 
        /* Power management */
@@ -263,4 +263,22 @@ struct ieee80211_sta *wcn36xx_priv_to_sta(struct wcn36xx_sta *sta_priv)
        return container_of((void *)sta_priv, struct ieee80211_sta, drv_priv);
 }
 
+static inline
+struct wcn36xx_vif *wcn36xx_vif_to_priv(struct ieee80211_vif *vif)
+{
+       return (struct wcn36xx_vif *) vif->drv_priv;
+}
+
+static inline
+struct ieee80211_vif *wcn36xx_priv_to_vif(struct wcn36xx_vif *vif_priv)
+{
+       return container_of((void *) vif_priv, struct ieee80211_vif, drv_priv);
+}
+
+static inline
+struct wcn36xx_sta *wcn36xx_sta_to_priv(struct ieee80211_sta *sta)
+{
+       return (struct wcn36xx_sta *)sta->drv_priv;
+}
+
 #endif /* _WCN36XX_H_ */
index 6af658e..d1bc51f 100644 (file)
@@ -321,7 +321,8 @@ brcmf_proto_bcdc_hdrpull(struct brcmf_pub *drvr, bool do_fws,
        if (pktbuf->len == 0)
                return -ENODATA;
 
-       *ifp = tmp_if;
+       if (ifp != NULL)
+               *ifp = tmp_if;
        return 0;
 }
 
@@ -351,6 +352,12 @@ brcmf_proto_bcdc_add_tdls_peer(struct brcmf_pub *drvr, int ifidx,
 {
 }
 
+static void brcmf_proto_bcdc_rxreorder(struct brcmf_if *ifp,
+                                      struct sk_buff *skb)
+{
+       brcmf_fws_rxreorder(ifp, skb);
+}
+
 int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
 {
        struct brcmf_bcdc *bcdc;
@@ -372,6 +379,7 @@ int brcmf_proto_bcdc_attach(struct brcmf_pub *drvr)
        drvr->proto->configure_addr_mode = brcmf_proto_bcdc_configure_addr_mode;
        drvr->proto->delete_peer = brcmf_proto_bcdc_delete_peer;
        drvr->proto->add_tdls_peer = brcmf_proto_bcdc_add_tdls_peer;
+       drvr->proto->rxreorder = brcmf_proto_bcdc_rxreorder;
        drvr->proto->pd = bcdc;
 
        drvr->hdrlen += BCDC_HEADER_LEN + BRCMF_PROT_FW_SIGNAL_MAX_TXBYTES;
index 8e02a47..2b24654 100644 (file)
@@ -216,7 +216,9 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q, struct sk_buff *pkt,
                      int prec);
 
 /* Receive frame for delivery to OS.  Callee disposes of rxp. */
-void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp);
+void brcmf_rx_frame(struct device *dev, struct sk_buff *rxp, bool handle_event);
+/* Receive async event packet from firmware. Callee disposes of rxp. */
+void brcmf_rx_event(struct device *dev, struct sk_buff *rxp);
 
 /* Indication from bus module regarding presence/insertion of dongle. */
 int brcmf_attach(struct device *dev, struct brcmf_mp_device *settings);
index 9a567e2..d0631b6 100644 (file)
@@ -250,6 +250,20 @@ struct parsed_vndr_ies {
        struct parsed_vndr_ie_info ie_info[VNDR_IE_PARSE_LIMIT];
 };
 
+static u8 nl80211_band_to_fwil(enum nl80211_band band)
+{
+       switch (band) {
+       case NL80211_BAND_2GHZ:
+               return WLC_BAND_2G;
+       case NL80211_BAND_5GHZ:
+               return WLC_BAND_5G;
+       default:
+               WARN_ON(1);
+               break;
+       }
+       return 0;
+}
+
 static u16 chandef_to_chanspec(struct brcmu_d11inf *d11inf,
                               struct cfg80211_chan_def *ch)
 {
@@ -1796,6 +1810,50 @@ enum nl80211_auth_type brcmf_war_auth_type(struct brcmf_if *ifp,
        return type;
 }
 
+static void brcmf_set_join_pref(struct brcmf_if *ifp,
+                               struct cfg80211_bss_selection *bss_select)
+{
+       struct brcmf_join_pref_params join_pref_params[2];
+       enum nl80211_band band;
+       int err, i = 0;
+
+       join_pref_params[i].len = 2;
+       join_pref_params[i].rssi_gain = 0;
+
+       if (bss_select->behaviour != NL80211_BSS_SELECT_ATTR_BAND_PREF)
+               brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_ASSOC_PREFER, WLC_BAND_AUTO);
+
+       switch (bss_select->behaviour) {
+       case __NL80211_BSS_SELECT_ATTR_INVALID:
+               brcmf_c_set_joinpref_default(ifp);
+               return;
+       case NL80211_BSS_SELECT_ATTR_BAND_PREF:
+               join_pref_params[i].type = BRCMF_JOIN_PREF_BAND;
+               band = bss_select->param.band_pref;
+               join_pref_params[i].band = nl80211_band_to_fwil(band);
+               i++;
+               break;
+       case NL80211_BSS_SELECT_ATTR_RSSI_ADJUST:
+               join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI_DELTA;
+               band = bss_select->param.adjust.band;
+               join_pref_params[i].band = nl80211_band_to_fwil(band);
+               join_pref_params[i].rssi_gain = bss_select->param.adjust.delta;
+               i++;
+               break;
+       case NL80211_BSS_SELECT_ATTR_RSSI:
+       default:
+               break;
+       }
+       join_pref_params[i].type = BRCMF_JOIN_PREF_RSSI;
+       join_pref_params[i].len = 2;
+       join_pref_params[i].rssi_gain = 0;
+       join_pref_params[i].band = 0;
+       err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
+                                      sizeof(join_pref_params));
+       if (err)
+               brcmf_err("Set join_pref error (%d)\n", err);
+}
+
 static s32
 brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
                       struct cfg80211_connect_params *sme)
@@ -1952,6 +2010,8 @@ brcmf_cfg80211_connect(struct wiphy *wiphy, struct net_device *ndev,
                ext_join_params->scan_le.nprobes = cpu_to_le32(-1);
        }
 
+       brcmf_set_join_pref(ifp, &sme->bss_select);
+
        err  = brcmf_fil_bsscfg_data_set(ifp, "join", ext_join_params,
                                         join_params_size);
        kfree(ext_join_params);
@@ -3608,7 +3668,8 @@ static void brcmf_configure_wowl(struct brcmf_cfg80211_info *cfg,
        if (!test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
                wowl_config |= BRCMF_WOWL_UNASSOC;
 
-       brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear", strlen("clear"));
+       brcmf_fil_iovar_data_set(ifp, "wowl_wakeind", "clear",
+                                sizeof(struct brcmf_wowl_wakeind_le));
        brcmf_fil_iovar_int_set(ifp, "wowl", wowl_config);
        brcmf_fil_iovar_int_set(ifp, "wowl_activate", 1);
        brcmf_bus_wowl_config(cfg->pub->bus_if, true);
@@ -6279,6 +6340,10 @@ static int brcmf_setup_wiphy(struct wiphy *wiphy, struct brcmf_if *ifp)
        wiphy->n_cipher_suites = ARRAY_SIZE(brcmf_cipher_suites);
        if (!brcmf_feat_is_enabled(ifp, BRCMF_FEAT_MFP))
                wiphy->n_cipher_suites--;
+       wiphy->bss_select_support = BIT(NL80211_BSS_SELECT_ATTR_RSSI) |
+                                   BIT(NL80211_BSS_SELECT_ATTR_BAND_PREF) |
+                                   BIT(NL80211_BSS_SELECT_ATTR_RSSI_ADJUST);
+
        wiphy->flags |= WIPHY_FLAG_PS_ON_BY_DEFAULT |
                        WIPHY_FLAG_OFFCHAN_TX |
                        WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
index 9e909e3..3e15d64 100644 (file)
@@ -38,7 +38,7 @@ const u8 ALLFFMAC[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
 #define BRCMF_DEFAULT_SCAN_CHANNEL_TIME        40
 #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME        40
 
-/* boost value for RSSI_DELTA in preferred join selection */
+/* default boost value for RSSI_DELTA in preferred join selection */
 #define BRCMF_JOIN_PREF_RSSI_BOOST     8
 
 #define BRCMF_DEFAULT_TXGLOM_SIZE      32  /* max tx frames in glom chain */
@@ -83,11 +83,31 @@ MODULE_PARM_DESC(ignore_probe_fail, "always succeed probe for debugging");
 static struct brcmfmac_platform_data *brcmfmac_pdata;
 struct brcmf_mp_global_t brcmf_mp_global;
 
+void brcmf_c_set_joinpref_default(struct brcmf_if *ifp)
+{
+       struct brcmf_join_pref_params join_pref_params[2];
+       int err;
+
+       /* Setup join_pref to select target by RSSI (boost on 5GHz) */
+       join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
+       join_pref_params[0].len = 2;
+       join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
+       join_pref_params[0].band = WLC_BAND_5G;
+
+       join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
+       join_pref_params[1].len = 2;
+       join_pref_params[1].rssi_gain = 0;
+       join_pref_params[1].band = 0;
+       err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
+                                      sizeof(join_pref_params));
+       if (err)
+               brcmf_err("Set join_pref error (%d)\n", err);
+}
+
 int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
 {
        s8 eventmask[BRCMF_EVENTING_MASK_LEN];
        u8 buf[BRCMF_DCMD_SMLEN];
-       struct brcmf_join_pref_params join_pref_params[2];
        struct brcmf_rev_info_le revinfo;
        struct brcmf_rev_info *ri;
        char *ptr;
@@ -154,19 +174,7 @@ int brcmf_c_preinit_dcmds(struct brcmf_if *ifp)
                goto done;
        }
 
-       /* Setup join_pref to select target by RSSI(with boost on 5GHz) */
-       join_pref_params[0].type = BRCMF_JOIN_PREF_RSSI_DELTA;
-       join_pref_params[0].len = 2;
-       join_pref_params[0].rssi_gain = BRCMF_JOIN_PREF_RSSI_BOOST;
-       join_pref_params[0].band = WLC_BAND_5G;
-       join_pref_params[1].type = BRCMF_JOIN_PREF_RSSI;
-       join_pref_params[1].len = 2;
-       join_pref_params[1].rssi_gain = 0;
-       join_pref_params[1].band = 0;
-       err = brcmf_fil_iovar_data_set(ifp, "join_pref", join_pref_params,
-                                      sizeof(join_pref_params));
-       if (err)
-               brcmf_err("Set join_pref error (%d)\n", err);
+       brcmf_c_set_joinpref_default(ifp);
 
        /* Setup event_msgs, enable E_IF */
        err = brcmf_fil_iovar_data_get(ifp, "event_msgs", eventmask,
index ff825cd..b590499 100644 (file)
 
 #define MAX_WAIT_FOR_8021X_TX                  msecs_to_jiffies(950)
 
-/* AMPDU rx reordering definitions */
-#define BRCMF_RXREORDER_FLOWID_OFFSET          0
-#define BRCMF_RXREORDER_MAXIDX_OFFSET          2
-#define BRCMF_RXREORDER_FLAGS_OFFSET           4
-#define BRCMF_RXREORDER_CURIDX_OFFSET          6
-#define BRCMF_RXREORDER_EXPIDX_OFFSET          8
-
-#define BRCMF_RXREORDER_DEL_FLOW               0x01
-#define BRCMF_RXREORDER_FLUSH_ALL              0x02
-#define BRCMF_RXREORDER_CURIDX_VALID           0x04
-#define BRCMF_RXREORDER_EXPIDX_VALID           0x08
-#define BRCMF_RXREORDER_NEW_HOLE               0x10
-
 #define BRCMF_BSSIDX_INVALID                   -1
 
 char *brcmf_ifname(struct brcmf_if *ifp)
@@ -313,15 +300,9 @@ void brcmf_txflowblock(struct device *dev, bool state)
 
 void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
 {
-       skb->dev = ifp->ndev;
-       skb->protocol = eth_type_trans(skb, skb->dev);
-
        if (skb->pkt_type == PACKET_MULTICAST)
                ifp->stats.multicast++;
 
-       /* Process special event packets */
-       brcmf_fweh_process_skb(ifp->drvr, skb);
-
        if (!(ifp->ndev->flags & IFF_UP)) {
                brcmu_pkt_buf_free_skb(skb);
                return;
@@ -341,226 +322,60 @@ void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb)
                netif_rx_ni(skb);
 }
 
-static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
-                                        u8 start, u8 end,
-                                        struct sk_buff_head *skb_list)
+static int brcmf_rx_hdrpull(struct brcmf_pub *drvr, struct sk_buff *skb,
+                           struct brcmf_if **ifp)
 {
-       /* initialize return list */
-       __skb_queue_head_init(skb_list);
+       int ret;
 
-       if (rfi->pend_pkts == 0) {
-               brcmf_dbg(INFO, "no packets in reorder queue\n");
-               return;
+       /* process and remove protocol-specific header */
+       ret = brcmf_proto_hdrpull(drvr, true, skb, ifp);
+
+       if (ret || !(*ifp) || !(*ifp)->ndev) {
+               if (ret != -ENODATA && *ifp)
+                       (*ifp)->stats.rx_errors++;
+               brcmu_pkt_buf_free_skb(skb);
+               return -ENODATA;
        }
 
-       do {
-               if (rfi->pktslots[start]) {
-                       __skb_queue_tail(skb_list, rfi->pktslots[start]);
-                       rfi->pktslots[start] = NULL;
-               }
-               start++;
-               if (start > rfi->max_idx)
-                       start = 0;
-       } while (start != end);
-       rfi->pend_pkts -= skb_queue_len(skb_list);
+       skb->protocol = eth_type_trans(skb, (*ifp)->ndev);
+       return 0;
 }
 
-static void brcmf_rxreorder_process_info(struct brcmf_if *ifp, u8 *reorder_data,
-                                        struct sk_buff *pkt)
+void brcmf_rx_frame(struct device *dev, struct sk_buff *skb, bool handle_event)
 {
-       u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
-       struct brcmf_ampdu_rx_reorder *rfi;
-       struct sk_buff_head reorder_list;
-       struct sk_buff *pnext;
-       u8 flags;
-       u32 buf_size;
-
-       flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
-       flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
-
-       /* validate flags and flow id */
-       if (flags == 0xFF) {
-               brcmf_err("invalid flags...so ignore this packet\n");
-               brcmf_netif_rx(ifp, pkt);
-               return;
-       }
-
-       rfi = ifp->drvr->reorder_flows[flow_id];
-       if (flags & BRCMF_RXREORDER_DEL_FLOW) {
-               brcmf_dbg(INFO, "flow-%d: delete\n",
-                         flow_id);
+       struct brcmf_if *ifp;
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_pub *drvr = bus_if->drvr;
 
-               if (rfi == NULL) {
-                       brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
-                                 flow_id);
-                       brcmf_netif_rx(ifp, pkt);
-                       return;
-               }
+       brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
 
-               brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
-                                            &reorder_list);
-               /* add the last packet */
-               __skb_queue_tail(&reorder_list, pkt);
-               kfree(rfi);
-               ifp->drvr->reorder_flows[flow_id] = NULL;
-               goto netif_rx;
-       }
-       /* from here on we need a flow reorder instance */
-       if (rfi == NULL) {
-               buf_size = sizeof(*rfi);
-               max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
-
-               buf_size += (max_idx + 1) * sizeof(pkt);
-
-               /* allocate space for flow reorder info */
-               brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
-                         flow_id, max_idx);
-               rfi = kzalloc(buf_size, GFP_ATOMIC);
-               if (rfi == NULL) {
-                       brcmf_err("failed to alloc buffer\n");
-                       brcmf_netif_rx(ifp, pkt);
-                       return;
-               }
+       if (brcmf_rx_hdrpull(drvr, skb, &ifp))
+               return;
 
-               ifp->drvr->reorder_flows[flow_id] = rfi;
-               rfi->pktslots = (struct sk_buff **)(rfi+1);
-               rfi->max_idx = max_idx;
-       }
-       if (flags & BRCMF_RXREORDER_NEW_HOLE)  {
-               if (rfi->pend_pkts) {
-                       brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
-                                                    rfi->exp_idx,
-                                                    &reorder_list);
-                       WARN_ON(rfi->pend_pkts);
-               } else {
-                       __skb_queue_head_init(&reorder_list);
-               }
-               rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
-               rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
-               rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
-               rfi->pktslots[rfi->cur_idx] = pkt;
-               rfi->pend_pkts++;
-               brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
-                         flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
-       } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
-               cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
-               exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
-
-               if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
-                       /* still in the current hole */
-                       /* enqueue the current on the buffer chain */
-                       if (rfi->pktslots[cur_idx] != NULL) {
-                               brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
-                               brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
-                               rfi->pktslots[cur_idx] = NULL;
-                       }
-                       rfi->pktslots[cur_idx] = pkt;
-                       rfi->pend_pkts++;
-                       rfi->cur_idx = cur_idx;
-                       brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
-                                 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
-
-                       /* can return now as there is no reorder
-                        * list to process.
-                        */
-                       return;
-               }
-               if (rfi->exp_idx == cur_idx) {
-                       if (rfi->pktslots[cur_idx] != NULL) {
-                               brcmf_dbg(INFO, "error buffer pending..free it\n");
-                               brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
-                               rfi->pktslots[cur_idx] = NULL;
-                       }
-                       rfi->pktslots[cur_idx] = pkt;
-                       rfi->pend_pkts++;
-
-                       /* got the expected one. flush from current to expected
-                        * and update expected
-                        */
-                       brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
-                                 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
-
-                       rfi->cur_idx = cur_idx;
-                       rfi->exp_idx = exp_idx;
-
-                       brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
-                                                    &reorder_list);
-                       brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
-                                 flow_id, skb_queue_len(&reorder_list),
-                                 rfi->pend_pkts);
-               } else {
-                       u8 end_idx;
-
-                       brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
-                                 flow_id, flags, rfi->cur_idx, rfi->exp_idx,
-                                 cur_idx, exp_idx);
-                       if (flags & BRCMF_RXREORDER_FLUSH_ALL)
-                               end_idx = rfi->exp_idx;
-                       else
-                               end_idx = exp_idx;
-
-                       /* flush pkts first */
-                       brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
-                                                    &reorder_list);
-
-                       if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
-                               __skb_queue_tail(&reorder_list, pkt);
-                       } else {
-                               rfi->pktslots[cur_idx] = pkt;
-                               rfi->pend_pkts++;
-                       }
-                       rfi->exp_idx = exp_idx;
-                       rfi->cur_idx = cur_idx;
-               }
+       if (brcmf_proto_is_reorder_skb(skb)) {
+               brcmf_proto_rxreorder(ifp, skb);
        } else {
-               /* explicity window move updating the expected index */
-               exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
-
-               brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
-                         flow_id, flags, rfi->exp_idx, exp_idx);
-               if (flags & BRCMF_RXREORDER_FLUSH_ALL)
-                       end_idx =  rfi->exp_idx;
-               else
-                       end_idx =  exp_idx;
+               /* Process special event packets */
+               if (handle_event)
+                       brcmf_fweh_process_skb(ifp->drvr, skb);
 
-               brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
-                                            &reorder_list);
-               __skb_queue_tail(&reorder_list, pkt);
-               /* set the new expected idx */
-               rfi->exp_idx = exp_idx;
-       }
-netif_rx:
-       skb_queue_walk_safe(&reorder_list, pkt, pnext) {
-               __skb_unlink(pkt, &reorder_list);
-               brcmf_netif_rx(ifp, pkt);
+               brcmf_netif_rx(ifp, skb);
        }
 }
 
-void brcmf_rx_frame(struct device *dev, struct sk_buff *skb)
+void brcmf_rx_event(struct device *dev, struct sk_buff *skb)
 {
        struct brcmf_if *ifp;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_pub *drvr = bus_if->drvr;
-       struct brcmf_skb_reorder_data *rd;
-       int ret;
 
-       brcmf_dbg(DATA, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
-
-       /* process and remove protocol-specific header */
-       ret = brcmf_proto_hdrpull(drvr, true, skb, &ifp);
+       brcmf_dbg(EVENT, "Enter: %s: rxp=%p\n", dev_name(dev), skb);
 
-       if (ret || !ifp || !ifp->ndev) {
-               if (ret != -ENODATA && ifp)
-                       ifp->stats.rx_errors++;
-               brcmu_pkt_buf_free_skb(skb);
+       if (brcmf_rx_hdrpull(drvr, skb, &ifp))
                return;
-       }
 
-       rd = (struct brcmf_skb_reorder_data *)skb->cb;
-       if (rd->reorder)
-               brcmf_rxreorder_process_info(ifp, rd->reorder, skb);
-       else
-               brcmf_netif_rx(ifp, skb);
+       brcmf_fweh_process_skb(ifp->drvr, skb);
+       brcmu_pkt_buf_free_skb(skb);
 }
 
 void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success)
index 7bdb6fe..647d3cc 100644 (file)
@@ -208,10 +208,6 @@ struct brcmf_if {
        u8 ipv6addr_idx;
 };
 
-struct brcmf_skb_reorder_data {
-       u8 *reorder;
-};
-
 int brcmf_netdev_wait_pend8021x(struct brcmf_if *ifp);
 
 /* Return pointer to interface name */
@@ -227,6 +223,7 @@ void brcmf_txflowblock_if(struct brcmf_if *ifp,
 void brcmf_txfinalize(struct brcmf_if *ifp, struct sk_buff *txp, bool success);
 void brcmf_netif_rx(struct brcmf_if *ifp, struct sk_buff *skb);
 void brcmf_net_setcarrier(struct brcmf_if *ifp, bool on);
+void brcmf_c_set_joinpref_default(struct brcmf_if *ifp);
 int __init brcmf_core_init(void);
 void __exit brcmf_core_exit(void);
 
index 7269056..c7c1e99 100644 (file)
@@ -29,6 +29,7 @@
 #define BRCMF_FW_MAX_NVRAM_SIZE                        64000
 #define BRCMF_FW_NVRAM_DEVPATH_LEN             19      /* devpath0=pcie/1/4/ */
 #define BRCMF_FW_NVRAM_PCIEDEV_LEN             10      /* pcie/1/4/ + \0 */
+#define BRCMF_FW_DEFAULT_BOARDREV              "boardrev=0xff"
 
 enum nvram_parser_state {
        IDLE,
@@ -51,6 +52,7 @@ enum nvram_parser_state {
  * @entry: start position of key,value entry.
  * @multi_dev_v1: detect pcie multi device v1 (compressed).
  * @multi_dev_v2: detect pcie multi device v2.
+ * @boardrev_found: nvram contains boardrev information.
  */
 struct nvram_parser {
        enum nvram_parser_state state;
@@ -63,6 +65,7 @@ struct nvram_parser {
        u32 entry;
        bool multi_dev_v1;
        bool multi_dev_v2;
+       bool boardrev_found;
 };
 
 /**
@@ -125,6 +128,8 @@ static enum nvram_parser_state brcmf_nvram_handle_key(struct nvram_parser *nvp)
                        nvp->multi_dev_v1 = true;
                if (strncmp(&nvp->data[nvp->entry], "pcie/", 5) == 0)
                        nvp->multi_dev_v2 = true;
+               if (strncmp(&nvp->data[nvp->entry], "boardrev", 8) == 0)
+                       nvp->boardrev_found = true;
        } else if (!is_nvram_char(c) || c == ' ') {
                brcmf_dbg(INFO, "warning: ln=%d:col=%d: '=' expected, skip invalid key entry\n",
                          nvp->line, nvp->column);
@@ -284,6 +289,8 @@ static void brcmf_fw_strip_multi_v1(struct nvram_parser *nvp, u16 domain_nr,
        while (i < nvp->nvram_len) {
                if ((nvp->nvram[i] - '0' == id) && (nvp->nvram[i + 1] == ':')) {
                        i += 2;
+                       if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
+                               nvp->boardrev_found = true;
                        while (nvp->nvram[i] != 0) {
                                nvram[j] = nvp->nvram[i];
                                i++;
@@ -335,6 +342,8 @@ static void brcmf_fw_strip_multi_v2(struct nvram_parser *nvp, u16 domain_nr,
        while (i < nvp->nvram_len - len) {
                if (strncmp(&nvp->nvram[i], prefix, len) == 0) {
                        i += len;
+                       if (strncmp(&nvp->nvram[i], "boardrev", 8) == 0)
+                               nvp->boardrev_found = true;
                        while (nvp->nvram[i] != 0) {
                                nvram[j] = nvp->nvram[i];
                                i++;
@@ -356,6 +365,18 @@ fail:
        nvp->nvram_len = 0;
 }
 
+static void brcmf_fw_add_defaults(struct nvram_parser *nvp)
+{
+       if (nvp->boardrev_found)
+               return;
+
+       memcpy(&nvp->nvram[nvp->nvram_len], &BRCMF_FW_DEFAULT_BOARDREV,
+              strlen(BRCMF_FW_DEFAULT_BOARDREV));
+       nvp->nvram_len += strlen(BRCMF_FW_DEFAULT_BOARDREV);
+       nvp->nvram[nvp->nvram_len] = '\0';
+       nvp->nvram_len++;
+}
+
 /* brcmf_nvram_strip :Takes a buffer of "<var>=<value>\n" lines read from a fil
  * and ending in a NUL. Removes carriage returns, empty lines, comment lines,
  * and converts newlines to NULs. Shortens buffer as needed and pads with NULs.
@@ -377,16 +398,21 @@ static void *brcmf_fw_nvram_strip(const u8 *data, size_t data_len,
                if (nvp.state == END)
                        break;
        }
-       if (nvp.multi_dev_v1)
+       if (nvp.multi_dev_v1) {
+               nvp.boardrev_found = false;
                brcmf_fw_strip_multi_v1(&nvp, domain_nr, bus_nr);
-       else if (nvp.multi_dev_v2)
+       } else if (nvp.multi_dev_v2) {
+               nvp.boardrev_found = false;
                brcmf_fw_strip_multi_v2(&nvp, domain_nr, bus_nr);
+       }
 
        if (nvp.nvram_len == 0) {
                kfree(nvp.nvram);
                return NULL;
        }
 
+       brcmf_fw_add_defaults(&nvp);
+
        pad = nvp.nvram_len;
        *new_length = roundup(nvp.nvram_len + 1, 4);
        while (pad != *new_length) {
index d414fbb..b390561 100644 (file)
@@ -371,6 +371,7 @@ int brcmf_fweh_activate_events(struct brcmf_if *ifp)
        int i, err;
        s8 eventmask[BRCMF_EVENTING_MASK_LEN];
 
+       memset(eventmask, 0, sizeof(eventmask));
        for (i = 0; i < BRCMF_E_LAST; i++) {
                if (ifp->drvr->fweh.evt_handler[i]) {
                        brcmf_dbg(EVENT, "enable event %s\n",
index 6b72df1..3a9a76d 100644 (file)
@@ -78,6 +78,7 @@
 #define BRCMF_C_SET_SCAN_CHANNEL_TIME          185
 #define BRCMF_C_SET_SCAN_UNASSOC_TIME          187
 #define BRCMF_C_SCB_DEAUTHENTICATE_FOR_REASON  201
+#define BRCMF_C_SET_ASSOC_PREFER               205
 #define BRCMF_C_GET_VALID_CHANNELS             217
 #define BRCMF_C_GET_KEY_PRIMARY                        235
 #define BRCMF_C_SET_KEY_PRIMARY                        236
index f82c9ab..5b30922 100644 (file)
@@ -92,6 +92,19 @@ enum brcmf_fws_tlv_len {
 };
 #undef BRCMF_FWS_TLV_DEF
 
+/* AMPDU rx reordering definitions */
+#define BRCMF_RXREORDER_FLOWID_OFFSET          0
+#define BRCMF_RXREORDER_MAXIDX_OFFSET          2
+#define BRCMF_RXREORDER_FLAGS_OFFSET           4
+#define BRCMF_RXREORDER_CURIDX_OFFSET          6
+#define BRCMF_RXREORDER_EXPIDX_OFFSET          8
+
+#define BRCMF_RXREORDER_DEL_FLOW               0x01
+#define BRCMF_RXREORDER_FLUSH_ALL              0x02
+#define BRCMF_RXREORDER_CURIDX_VALID           0x04
+#define BRCMF_RXREORDER_EXPIDX_VALID           0x08
+#define BRCMF_RXREORDER_NEW_HOLE               0x10
+
 #ifdef DEBUG
 /*
  * brcmf_fws_tlv_names - array of tlv names.
@@ -1614,6 +1627,202 @@ static int brcmf_fws_notify_bcmc_credit_support(struct brcmf_if *ifp,
        return 0;
 }
 
+static void brcmf_rxreorder_get_skb_list(struct brcmf_ampdu_rx_reorder *rfi,
+                                        u8 start, u8 end,
+                                        struct sk_buff_head *skb_list)
+{
+       /* initialize return list */
+       __skb_queue_head_init(skb_list);
+
+       if (rfi->pend_pkts == 0) {
+               brcmf_dbg(INFO, "no packets in reorder queue\n");
+               return;
+       }
+
+       do {
+               if (rfi->pktslots[start]) {
+                       __skb_queue_tail(skb_list, rfi->pktslots[start]);
+                       rfi->pktslots[start] = NULL;
+               }
+               start++;
+               if (start > rfi->max_idx)
+                       start = 0;
+       } while (start != end);
+       rfi->pend_pkts -= skb_queue_len(skb_list);
+}
+
+void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *pkt)
+{
+       u8 *reorder_data;
+       u8 flow_id, max_idx, cur_idx, exp_idx, end_idx;
+       struct brcmf_ampdu_rx_reorder *rfi;
+       struct sk_buff_head reorder_list;
+       struct sk_buff *pnext;
+       u8 flags;
+       u32 buf_size;
+
+       reorder_data = ((struct brcmf_skb_reorder_data *)pkt->cb)->reorder;
+       flow_id = reorder_data[BRCMF_RXREORDER_FLOWID_OFFSET];
+       flags = reorder_data[BRCMF_RXREORDER_FLAGS_OFFSET];
+
+       /* validate flags and flow id */
+       if (flags == 0xFF) {
+               brcmf_err("invalid flags...so ignore this packet\n");
+               brcmf_netif_rx(ifp, pkt);
+               return;
+       }
+
+       rfi = ifp->drvr->reorder_flows[flow_id];
+       if (flags & BRCMF_RXREORDER_DEL_FLOW) {
+               brcmf_dbg(INFO, "flow-%d: delete\n",
+                         flow_id);
+
+               if (rfi == NULL) {
+                       brcmf_dbg(INFO, "received flags to cleanup, but no flow (%d) yet\n",
+                                 flow_id);
+                       brcmf_netif_rx(ifp, pkt);
+                       return;
+               }
+
+               brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, rfi->exp_idx,
+                                            &reorder_list);
+               /* add the last packet */
+               __skb_queue_tail(&reorder_list, pkt);
+               kfree(rfi);
+               ifp->drvr->reorder_flows[flow_id] = NULL;
+               goto netif_rx;
+       }
+       /* from here on we need a flow reorder instance */
+       if (rfi == NULL) {
+               buf_size = sizeof(*rfi);
+               max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
+
+               buf_size += (max_idx + 1) * sizeof(pkt);
+
+               /* allocate space for flow reorder info */
+               brcmf_dbg(INFO, "flow-%d: start, maxidx %d\n",
+                         flow_id, max_idx);
+               rfi = kzalloc(buf_size, GFP_ATOMIC);
+               if (rfi == NULL) {
+                       brcmf_err("failed to alloc buffer\n");
+                       brcmf_netif_rx(ifp, pkt);
+                       return;
+               }
+
+               ifp->drvr->reorder_flows[flow_id] = rfi;
+               rfi->pktslots = (struct sk_buff **)(rfi + 1);
+               rfi->max_idx = max_idx;
+       }
+       if (flags & BRCMF_RXREORDER_NEW_HOLE)  {
+               if (rfi->pend_pkts) {
+                       brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx,
+                                                    rfi->exp_idx,
+                                                    &reorder_list);
+                       WARN_ON(rfi->pend_pkts);
+               } else {
+                       __skb_queue_head_init(&reorder_list);
+               }
+               rfi->cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
+               rfi->exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
+               rfi->max_idx = reorder_data[BRCMF_RXREORDER_MAXIDX_OFFSET];
+               rfi->pktslots[rfi->cur_idx] = pkt;
+               rfi->pend_pkts++;
+               brcmf_dbg(DATA, "flow-%d: new hole %d (%d), pending %d\n",
+                         flow_id, rfi->cur_idx, rfi->exp_idx, rfi->pend_pkts);
+       } else if (flags & BRCMF_RXREORDER_CURIDX_VALID) {
+               cur_idx = reorder_data[BRCMF_RXREORDER_CURIDX_OFFSET];
+               exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
+
+               if ((exp_idx == rfi->exp_idx) && (cur_idx != rfi->exp_idx)) {
+                       /* still in the current hole */
+                       /* enqueue the current on the buffer chain */
+                       if (rfi->pktslots[cur_idx] != NULL) {
+                               brcmf_dbg(INFO, "HOLE: ERROR buffer pending..free it\n");
+                               brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
+                               rfi->pktslots[cur_idx] = NULL;
+                       }
+                       rfi->pktslots[cur_idx] = pkt;
+                       rfi->pend_pkts++;
+                       rfi->cur_idx = cur_idx;
+                       brcmf_dbg(DATA, "flow-%d: store pkt %d (%d), pending %d\n",
+                                 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
+
+                       /* can return now as there is no reorder
+                        * list to process.
+                        */
+                       return;
+               }
+               if (rfi->exp_idx == cur_idx) {
+                       if (rfi->pktslots[cur_idx] != NULL) {
+                               brcmf_dbg(INFO, "error buffer pending..free it\n");
+                               brcmu_pkt_buf_free_skb(rfi->pktslots[cur_idx]);
+                               rfi->pktslots[cur_idx] = NULL;
+                       }
+                       rfi->pktslots[cur_idx] = pkt;
+                       rfi->pend_pkts++;
+
+                       /* got the expected one. flush from current to expected
+                        * and update expected
+                        */
+                       brcmf_dbg(DATA, "flow-%d: expected %d (%d), pending %d\n",
+                                 flow_id, cur_idx, exp_idx, rfi->pend_pkts);
+
+                       rfi->cur_idx = cur_idx;
+                       rfi->exp_idx = exp_idx;
+
+                       brcmf_rxreorder_get_skb_list(rfi, cur_idx, exp_idx,
+                                                    &reorder_list);
+                       brcmf_dbg(DATA, "flow-%d: freeing buffers %d, pending %d\n",
+                                 flow_id, skb_queue_len(&reorder_list),
+                                 rfi->pend_pkts);
+               } else {
+                       u8 end_idx;
+
+                       brcmf_dbg(DATA, "flow-%d (0x%x): both moved, old %d/%d, new %d/%d\n",
+                                 flow_id, flags, rfi->cur_idx, rfi->exp_idx,
+                                 cur_idx, exp_idx);
+                       if (flags & BRCMF_RXREORDER_FLUSH_ALL)
+                               end_idx = rfi->exp_idx;
+                       else
+                               end_idx = exp_idx;
+
+                       /* flush pkts first */
+                       brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
+                                                    &reorder_list);
+
+                       if (exp_idx == ((cur_idx + 1) % (rfi->max_idx + 1))) {
+                               __skb_queue_tail(&reorder_list, pkt);
+                       } else {
+                               rfi->pktslots[cur_idx] = pkt;
+                               rfi->pend_pkts++;
+                       }
+                       rfi->exp_idx = exp_idx;
+                       rfi->cur_idx = cur_idx;
+               }
+       } else {
+               /* explicity window move updating the expected index */
+               exp_idx = reorder_data[BRCMF_RXREORDER_EXPIDX_OFFSET];
+
+               brcmf_dbg(DATA, "flow-%d (0x%x): change expected: %d -> %d\n",
+                         flow_id, flags, rfi->exp_idx, exp_idx);
+               if (flags & BRCMF_RXREORDER_FLUSH_ALL)
+                       end_idx =  rfi->exp_idx;
+               else
+                       end_idx =  exp_idx;
+
+               brcmf_rxreorder_get_skb_list(rfi, rfi->exp_idx, end_idx,
+                                            &reorder_list);
+               __skb_queue_tail(&reorder_list, pkt);
+               /* set the new expected idx */
+               rfi->exp_idx = exp_idx;
+       }
+netif_rx:
+       skb_queue_walk_safe(&reorder_list, pkt, pnext) {
+               __skb_unlink(pkt, &reorder_list);
+               brcmf_netif_rx(ifp, pkt);
+       }
+}
+
 void brcmf_fws_hdrpull(struct brcmf_if *ifp, s16 siglen, struct sk_buff *skb)
 {
        struct brcmf_skb_reorder_data *rd;
index a36bac1..ef0ad85 100644 (file)
@@ -29,5 +29,6 @@ void brcmf_fws_add_interface(struct brcmf_if *ifp);
 void brcmf_fws_del_interface(struct brcmf_if *ifp);
 void brcmf_fws_bustxfail(struct brcmf_fws_info *fws, struct sk_buff *skb);
 void brcmf_fws_bus_blocked(struct brcmf_pub *drvr, bool flow_blocked);
+void brcmf_fws_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb);
 
 #endif /* FWSIGNAL_H_ */
index 9229667..68f1ce0 100644 (file)
@@ -20,6 +20,7 @@
 
 #include <linux/types.h>
 #include <linux/netdevice.h>
+#include <linux/etherdevice.h>
 
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
@@ -526,6 +527,9 @@ static int brcmf_msgbuf_hdrpull(struct brcmf_pub *drvr, bool do_fws,
        return -ENODEV;
 }
 
+static void brcmf_msgbuf_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
+{
+}
 
 static void
 brcmf_msgbuf_remove_flowring(struct brcmf_msgbuf *msgbuf, u16 flowid)
@@ -1075,28 +1079,13 @@ static void brcmf_msgbuf_rxbuf_event_post(struct brcmf_msgbuf *msgbuf)
 }
 
 
-static void
-brcmf_msgbuf_rx_skb(struct brcmf_msgbuf *msgbuf, struct sk_buff *skb,
-                   u8 ifidx)
-{
-       struct brcmf_if *ifp;
-
-       ifp = brcmf_get_ifp(msgbuf->drvr, ifidx);
-       if (!ifp || !ifp->ndev) {
-               brcmf_err("Received pkt for invalid ifidx %d\n", ifidx);
-               brcmu_pkt_buf_free_skb(skb);
-               return;
-       }
-       brcmf_netif_rx(ifp, skb);
-}
-
-
 static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
 {
        struct msgbuf_rx_event *event;
        u32 idx;
        u16 buflen;
        struct sk_buff *skb;
+       struct brcmf_if *ifp;
 
        event = (struct msgbuf_rx_event *)buf;
        idx = le32_to_cpu(event->msg.request_id);
@@ -1116,7 +1105,19 @@ static void brcmf_msgbuf_process_event(struct brcmf_msgbuf *msgbuf, void *buf)
 
        skb_trim(skb, buflen);
 
-       brcmf_msgbuf_rx_skb(msgbuf, skb, event->msg.ifidx);
+       ifp = brcmf_get_ifp(msgbuf->drvr, event->msg.ifidx);
+       if (!ifp || !ifp->ndev) {
+               brcmf_err("Received pkt for invalid ifidx %d\n",
+                         event->msg.ifidx);
+               goto exit;
+       }
+
+       skb->protocol = eth_type_trans(skb, ifp->ndev);
+
+       brcmf_fweh_process_skb(ifp->drvr, skb);
+
+exit:
+       brcmu_pkt_buf_free_skb(skb);
 }
 
 
@@ -1128,6 +1129,7 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
        u16 data_offset;
        u16 buflen;
        u32 idx;
+       struct brcmf_if *ifp;
 
        brcmf_msgbuf_update_rxbufpost_count(msgbuf, 1);
 
@@ -1148,7 +1150,14 @@ brcmf_msgbuf_process_rx_complete(struct brcmf_msgbuf *msgbuf, void *buf)
 
        skb_trim(skb, buflen);
 
-       brcmf_msgbuf_rx_skb(msgbuf, skb, rx_complete->msg.ifidx);
+       ifp = brcmf_get_ifp(msgbuf->drvr, rx_complete->msg.ifidx);
+       if (!ifp || !ifp->ndev) {
+               brcmf_err("Received pkt for invalid ifidx %d\n",
+                         rx_complete->msg.ifidx);
+               brcmu_pkt_buf_free_skb(skb);
+               return;
+       }
+       brcmf_netif_rx(ifp, skb);
 }
 
 
@@ -1460,6 +1469,7 @@ int brcmf_proto_msgbuf_attach(struct brcmf_pub *drvr)
        drvr->proto->configure_addr_mode = brcmf_msgbuf_configure_addr_mode;
        drvr->proto->delete_peer = brcmf_msgbuf_delete_peer;
        drvr->proto->add_tdls_peer = brcmf_msgbuf_add_tdls_peer;
+       drvr->proto->rxreorder = brcmf_msgbuf_rxreorder;
        drvr->proto->pd = msgbuf;
 
        init_waitqueue_head(&msgbuf->ioctl_resp_wait);
index c2ac91d..a70cda6 100644 (file)
@@ -1266,7 +1266,7 @@ static void
 brcmf_p2p_stop_wait_next_action_frame(struct brcmf_cfg80211_info *cfg)
 {
        struct brcmf_p2p_info *p2p = &cfg->p2p;
-       struct brcmf_if *ifp = cfg->escan_info.ifp;
+       struct brcmf_if *ifp = p2p->bss_idx[P2PAPI_BSSCFG_PRIMARY].vif->ifp;
 
        if (test_bit(BRCMF_P2P_STATUS_SENDING_ACT_FRAME, &p2p->status) &&
            (test_bit(BRCMF_P2P_STATUS_ACTION_TX_COMPLETED, &p2p->status) ||
index d55119d..57531f4 100644 (file)
@@ -22,6 +22,9 @@ enum proto_addr_mode {
        ADDR_DIRECT
 };
 
+struct brcmf_skb_reorder_data {
+       u8 *reorder;
+};
 
 struct brcmf_proto {
        int (*hdrpull)(struct brcmf_pub *drvr, bool do_fws,
@@ -38,6 +41,7 @@ struct brcmf_proto {
                            u8 peer[ETH_ALEN]);
        void (*add_tdls_peer)(struct brcmf_pub *drvr, int ifidx,
                              u8 peer[ETH_ALEN]);
+       void (*rxreorder)(struct brcmf_if *ifp, struct sk_buff *skb);
        void *pd;
 };
 
@@ -91,6 +95,18 @@ brcmf_proto_add_tdls_peer(struct brcmf_pub *drvr, int ifidx, u8 peer[ETH_ALEN])
 {
        drvr->proto->add_tdls_peer(drvr, ifidx, peer);
 }
+static inline bool brcmf_proto_is_reorder_skb(struct sk_buff *skb)
+{
+       struct brcmf_skb_reorder_data *rd;
+
+       rd = (struct brcmf_skb_reorder_data *)skb->cb;
+       return !!rd->reorder;
+}
 
+static inline void
+brcmf_proto_rxreorder(struct brcmf_if *ifp, struct sk_buff *skb)
+{
+       ifp->drvr->proto->rxreorder(ifp, skb);
+}
 
 #endif /* BRCMFMAC_PROTO_H */
index 48d7467..4252fa8 100644 (file)
@@ -1294,6 +1294,17 @@ static inline u8 brcmf_sdio_getdatoffset(u8 *swheader)
        return (u8)((hdrvalue & SDPCM_DOFFSET_MASK) >> SDPCM_DOFFSET_SHIFT);
 }
 
+static inline bool brcmf_sdio_fromevntchan(u8 *swheader)
+{
+       u32 hdrvalue;
+       u8 ret;
+
+       hdrvalue = *(u32 *)swheader;
+       ret = (u8)((hdrvalue & SDPCM_CHANNEL_MASK) >> SDPCM_CHANNEL_SHIFT);
+
+       return (ret == SDPCM_EVENT_CHANNEL);
+}
+
 static int brcmf_sdio_hdparse(struct brcmf_sdio *bus, u8 *header,
                              struct brcmf_sdio_hdrinfo *rd,
                              enum brcmf_sdio_frmtype type)
@@ -1641,7 +1652,11 @@ static u8 brcmf_sdio_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                           pfirst->len, pfirst->next,
                                           pfirst->prev);
                        skb_unlink(pfirst, &bus->glom);
-                       brcmf_rx_frame(bus->sdiodev->dev, pfirst);
+                       if (brcmf_sdio_fromevntchan(pfirst->data))
+                               brcmf_rx_event(bus->sdiodev->dev, pfirst);
+                       else
+                               brcmf_rx_frame(bus->sdiodev->dev, pfirst,
+                                              false);
                        bus->sdcnt.rxglompkts++;
                }
 
@@ -1967,18 +1982,19 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                __skb_trim(pkt, rd->len);
                skb_pull(pkt, rd->dat_offset);
 
+               if (pkt->len == 0)
+                       brcmu_pkt_buf_free_skb(pkt);
+               else if (rd->channel == SDPCM_EVENT_CHANNEL)
+                       brcmf_rx_event(bus->sdiodev->dev, pkt);
+               else
+                       brcmf_rx_frame(bus->sdiodev->dev, pkt,
+                                      false);
+
                /* prepare the descriptor for the next read */
                rd->len = rd->len_nxtfrm << 4;
                rd->len_nxtfrm = 0;
                /* treat all packet as event if we don't know */
                rd->channel = SDPCM_EVENT_CHANNEL;
-
-               if (pkt->len == 0) {
-                       brcmu_pkt_buf_free_skb(pkt);
-                       continue;
-               }
-
-               brcmf_rx_frame(bus->sdiodev->dev, pkt);
        }
 
        rxcount = maxframes - rxleft;
index 869eb82..aa0b2a1 100644 (file)
@@ -514,7 +514,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
 
        if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
                skb_put(skb, urb->actual_length);
-               brcmf_rx_frame(devinfo->dev, skb);
+               brcmf_rx_frame(devinfo->dev, skb, true);
                brcmf_usb_rx_refill(devinfo, req);
        } else {
                brcmu_pkt_buf_free_skb(skb);
index 48e8737..4f495d9 100644 (file)
@@ -1280,7 +1280,10 @@ static void iwl_req_fw_callback(const struct firmware *ucode_raw, void *context)
        if (err)
                goto try_again;
 
-       api_ver = drv->fw.ucode_ver;
+       if (fw_has_api(&drv->fw.ucode_capa, IWL_UCODE_TLV_API_NEW_VERSION))
+               api_ver = drv->fw.ucode_ver;
+       else
+               api_ver = IWL_UCODE_API(drv->fw.ucode_ver);
 
        /*
         * api_ver should match the api version forming part of the
index 843232b..37dc09e 100644 (file)
@@ -251,6 +251,7 @@ typedef unsigned int __bitwise__ iwl_ucode_tlv_api_t;
  * @IWL_UCODE_TLV_API_WIFI_MCC_UPDATE: ucode supports MCC updates with source.
  * @IWL_UCODE_TLV_API_WIDE_CMD_HDR: ucode supports wide command header
  * @IWL_UCODE_TLV_API_LQ_SS_PARAMS: Configure STBC/BFER via LQ CMD ss_params
+ * @IWL_UCODE_TLV_API_NEW_VERSION: new versioning format
  * @IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY: scan APIs use 8-level priority
  *     instead of 3.
  * @IWL_UCODE_TLV_API_TX_POWER_CHAIN: TX power API has larger command size
@@ -263,6 +264,7 @@ enum iwl_ucode_tlv_api {
        IWL_UCODE_TLV_API_WIFI_MCC_UPDATE       = (__force iwl_ucode_tlv_api_t)9,
        IWL_UCODE_TLV_API_WIDE_CMD_HDR          = (__force iwl_ucode_tlv_api_t)14,
        IWL_UCODE_TLV_API_LQ_SS_PARAMS          = (__force iwl_ucode_tlv_api_t)18,
+       IWL_UCODE_TLV_API_NEW_VERSION           = (__force iwl_ucode_tlv_api_t)20,
        IWL_UCODE_TLV_API_EXT_SCAN_PRIORITY     = (__force iwl_ucode_tlv_api_t)24,
        IWL_UCODE_TLV_API_TX_POWER_CHAIN        = (__force iwl_ucode_tlv_api_t)27,
 
index 333c1a2..6700387 100644 (file)
@@ -19,6 +19,7 @@
 #include <linux/module.h>
 #include <linux/types.h>
 #include <linux/delay.h>
+#include <linux/ktime.h>
 
 #include <asm/uaccess.h>
 #include <asm/io.h>
@@ -113,7 +114,7 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
        u32 counter = 0;
-       struct timeval current_time;
+       struct timespec64 current_ts64;
        DEBUG(SHOW_FUNCTION_CALLS, "isl38xx trigger device\n");
 #endif
 
@@ -121,22 +122,22 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
        if (asleep) {
                /* device is in powersave, trigger the device for wakeup */
 #if VERBOSE > SHOW_ERROR_MESSAGES
-               do_gettimeofday(&current_time);
-               DEBUG(SHOW_TRACING, "%08li.%08li Device wakeup triggered\n",
-                     current_time.tv_sec, (long)current_time.tv_usec);
+               ktime_get_real_ts64(&current_ts64);
+               DEBUG(SHOW_TRACING, "%lld.%09ld Device wakeup triggered\n",
+                     (s64)current_ts64.tv_sec, current_ts64.tv_nsec);
 
-               DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
-                     current_time.tv_sec, (long)current_time.tv_usec,
+               DEBUG(SHOW_TRACING, "%lld.%09ld Device register read %08x\n",
+                     (s64)current_ts64.tv_sec, current_ts64.tv_nsec,
                      readl(device_base + ISL38XX_CTRL_STAT_REG));
 #endif
 
                reg = readl(device_base + ISL38XX_INT_IDENT_REG);
                if (reg == 0xabadface) {
 #if VERBOSE > SHOW_ERROR_MESSAGES
-                       do_gettimeofday(&current_time);
+                       ktime_get_real_ts64(&current_ts64);
                        DEBUG(SHOW_TRACING,
-                             "%08li.%08li Device register abadface\n",
-                             current_time.tv_sec, (long)current_time.tv_usec);
+                             "%lld.%09ld Device register abadface\n",
+                             (s64)current_ts64.tv_sec, current_ts64.tv_nsec);
 #endif
                        /* read the Device Status Register until Sleepmode bit is set */
                        while (reg = readl(device_base + ISL38XX_CTRL_STAT_REG),
@@ -149,13 +150,13 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
 
 #if VERBOSE > SHOW_ERROR_MESSAGES
                        DEBUG(SHOW_TRACING,
-                             "%08li.%08li Device register read %08x\n",
-                             current_time.tv_sec, (long)current_time.tv_usec,
+                             "%lld.%09ld Device register read %08x\n",
+                             (s64)current_ts64.tv_sec, current_ts64.tv_nsec,
                              readl(device_base + ISL38XX_CTRL_STAT_REG));
-                       do_gettimeofday(&current_time);
+                       ktime_get_real_ts64(&current_ts64);
                        DEBUG(SHOW_TRACING,
-                             "%08li.%08li Device asleep counter %i\n",
-                             current_time.tv_sec, (long)current_time.tv_usec,
+                             "%lld.%09ld Device asleep counter %i\n",
+                             (s64)current_ts64.tv_sec, current_ts64.tv_nsec,
                              counter);
 #endif
                }
@@ -168,9 +169,9 @@ isl38xx_trigger_device(int asleep, void __iomem *device_base)
 
                /* perform another read on the Device Status Register */
                reg = readl(device_base + ISL38XX_CTRL_STAT_REG);
-               do_gettimeofday(&current_time);
-               DEBUG(SHOW_TRACING, "%08li.%08li Device register read %08x\n",
-                     current_time.tv_sec, (long)current_time.tv_usec, reg);
+               ktime_get_real_ts64(&current_ts64);
+               DEBUG(SHOW_TRACING, "%lld.%00ld Device register read %08x\n",
+                     (s64)current_ts64.tv_sec, current_ts64.tv_nsec, reg);
 #endif
        } else {
                /* device is (still) awake  */
index 6db202f..ff948a9 100644 (file)
@@ -3344,6 +3344,7 @@ static int mwifiex_cfg80211_resume(struct wiphy *wiphy)
        struct mwifiex_ds_wakeup_reason wakeup_reason;
        struct cfg80211_wowlan_wakeup wakeup_report;
        int i;
+       bool report_wakeup_reason = true;
 
        for (i = 0; i < adapter->priv_num; i++) {
                priv = adapter->priv[i];
@@ -3354,6 +3355,9 @@ static int mwifiex_cfg80211_resume(struct wiphy *wiphy)
                }
        }
 
+       if (!wiphy->wowlan_config)
+               goto done;
+
        priv = mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA);
        mwifiex_get_wakeup_reason(priv, HostCmd_ACT_GEN_GET, MWIFIEX_SYNC_CMD,
                                  &wakeup_reason);
@@ -3386,23 +3390,20 @@ static int mwifiex_cfg80211_resume(struct wiphy *wiphy)
                if (wiphy->wowlan_config->n_patterns)
                        wakeup_report.pattern_idx = 1;
                break;
-       case CONTROL_FRAME_MATCHED:
-               break;
-       case    MANAGEMENT_FRAME_MATCHED:
-               break;
        case GTK_REKEY_FAILURE:
                if (wiphy->wowlan_config->gtk_rekey_failure)
                        wakeup_report.gtk_rekey_failure = true;
                break;
        default:
+               report_wakeup_reason = false;
                break;
        }
 
-       if ((wakeup_reason.hs_wakeup_reason > 0) &&
-           (wakeup_reason.hs_wakeup_reason <= 7))
+       if (report_wakeup_reason)
                cfg80211_report_wowlan_wakeup(&priv->wdev, &wakeup_report,
                                              GFP_KERNEL);
 
+done:
        if (adapter->nd_info) {
                for (i = 0 ; i < adapter->nd_info->n_matches ; i++)
                        kfree(adapter->nd_info->matches[i]);
index a12adee..6bc2011 100644 (file)
@@ -104,6 +104,47 @@ mwifiex_clean_cmd_node(struct mwifiex_adapter *adapter,
        }
 }
 
+/*
+ * This function returns a command to the command free queue.
+ *
+ * The function also calls the completion callback if required, before
+ * cleaning the command node and re-inserting it into the free queue.
+ */
+static void
+mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
+                            struct cmd_ctrl_node *cmd_node)
+{
+       unsigned long flags;
+
+       if (!cmd_node)
+               return;
+
+       if (cmd_node->wait_q_enabled)
+               mwifiex_complete_cmd(adapter, cmd_node);
+       /* Clean the node */
+       mwifiex_clean_cmd_node(adapter, cmd_node);
+
+       /* Insert node into cmd_free_q */
+       spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
+       list_add_tail(&cmd_node->list, &adapter->cmd_free_q);
+       spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
+}
+
+/* This function reuses a command node. */
+void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
+                             struct cmd_ctrl_node *cmd_node)
+{
+       struct host_cmd_ds_command *host_cmd = (void *)cmd_node->cmd_skb->data;
+
+       mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+
+       atomic_dec(&adapter->cmd_pending);
+       mwifiex_dbg(adapter, CMD,
+                   "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
+               le16_to_cpu(host_cmd->command),
+               atomic_read(&adapter->cmd_pending));
+}
+
 /*
  * This function sends a host command to the firmware.
  *
@@ -613,47 +654,6 @@ int mwifiex_send_cmd(struct mwifiex_private *priv, u16 cmd_no,
        return ret;
 }
 
-/*
- * This function returns a command to the command free queue.
- *
- * The function also calls the completion callback if required, before
- * cleaning the command node and re-inserting it into the free queue.
- */
-void
-mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
-                            struct cmd_ctrl_node *cmd_node)
-{
-       unsigned long flags;
-
-       if (!cmd_node)
-               return;
-
-       if (cmd_node->wait_q_enabled)
-               mwifiex_complete_cmd(adapter, cmd_node);
-       /* Clean the node */
-       mwifiex_clean_cmd_node(adapter, cmd_node);
-
-       /* Insert node into cmd_free_q */
-       spin_lock_irqsave(&adapter->cmd_free_q_lock, flags);
-       list_add_tail(&cmd_node->list, &adapter->cmd_free_q);
-       spin_unlock_irqrestore(&adapter->cmd_free_q_lock, flags);
-}
-
-/* This function reuses a command node. */
-void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
-                             struct cmd_ctrl_node *cmd_node)
-{
-       struct host_cmd_ds_command *host_cmd = (void *)cmd_node->cmd_skb->data;
-
-       mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
-
-       atomic_dec(&adapter->cmd_pending);
-       mwifiex_dbg(adapter, CMD,
-                   "cmd: FREE_CMD: cmd=%#x, cmd_pending=%d\n",
-               le16_to_cpu(host_cmd->command),
-               atomic_read(&adapter->cmd_pending));
-}
-
 /*
  * This function queues a command to the command pending queue.
  *
@@ -991,6 +991,23 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
                adapter->if_ops.card_reset(adapter);
 }
 
+void
+mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter)
+{
+       struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
+       unsigned long flags;
+
+       /* Cancel all pending scan command */
+       spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
+       list_for_each_entry_safe(cmd_node, tmp_node,
+                                &adapter->scan_pending_q, list) {
+               list_del(&cmd_node->list);
+               cmd_node->wait_q_enabled = false;
+               mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
+       }
+       spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+}
+
 /*
  * This function cancels all the pending commands.
  *
@@ -1009,9 +1026,9 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
        spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
        /* Cancel current cmd */
        if ((adapter->curr_cmd) && (adapter->curr_cmd->wait_q_enabled)) {
-               adapter->curr_cmd->wait_q_enabled = false;
                adapter->cmd_wait_q.status = -1;
                mwifiex_complete_cmd(adapter, adapter->curr_cmd);
+               adapter->curr_cmd->wait_q_enabled = false;
                /* no recycle probably wait for response */
        }
        /* Cancel all pending command */
@@ -1029,16 +1046,7 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
        spin_unlock_irqrestore(&adapter->cmd_pending_q_lock, flags);
        spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, cmd_flags);
 
-       /* Cancel all pending scan command */
-       spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
-       list_for_each_entry_safe(cmd_node, tmp_node,
-                                &adapter->scan_pending_q, list) {
-               list_del(&cmd_node->list);
-
-               cmd_node->wait_q_enabled = false;
-               mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
-       }
-       spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+       mwifiex_cancel_pending_scan_cmd(adapter);
 
        if (adapter->scan_processing) {
                spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
@@ -1070,9 +1078,8 @@ mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter)
 void
 mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
 {
-       struct cmd_ctrl_node *cmd_node = NULL, *tmp_node = NULL;
+       struct cmd_ctrl_node *cmd_node = NULL;
        unsigned long cmd_flags;
-       unsigned long scan_pending_q_flags;
        struct mwifiex_private *priv;
        int i;
 
@@ -1094,17 +1101,7 @@ mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter)
                mwifiex_recycle_cmd_node(adapter, cmd_node);
        }
 
-       /* Cancel all pending scan command */
-       spin_lock_irqsave(&adapter->scan_pending_q_lock,
-                         scan_pending_q_flags);
-       list_for_each_entry_safe(cmd_node, tmp_node,
-                                &adapter->scan_pending_q, list) {
-               list_del(&cmd_node->list);
-               cmd_node->wait_q_enabled = false;
-               mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
-       }
-       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
-                              scan_pending_q_flags);
+       mwifiex_cancel_pending_scan_cmd(adapter);
 
        if (adapter->scan_processing) {
                spin_lock_irqsave(&adapter->mwifiex_cmd_lock, cmd_flags);
index 04b975c..8b67a55 100644 (file)
@@ -702,6 +702,13 @@ mwifiex_close(struct net_device *dev)
                priv->scan_aborting = true;
        }
 
+       if (priv->sched_scanning) {
+               mwifiex_dbg(priv->adapter, INFO,
+                           "aborting bgscan on ndo_stop\n");
+               mwifiex_stop_bg_scan(priv);
+               cfg80211_sched_scan_stopped(priv->wdev.wiphy);
+       }
+
        return 0;
 }
 
@@ -753,13 +760,6 @@ int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
 
        mwifiex_queue_main_work(priv->adapter);
 
-       if (priv->sched_scanning) {
-               mwifiex_dbg(priv->adapter, INFO,
-                           "aborting bgscan on ndo_stop\n");
-               mwifiex_stop_bg_scan(priv);
-               cfg80211_sched_scan_stopped(priv->wdev.wiphy);
-       }
-
        return 0;
 }
 
@@ -1434,7 +1434,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
        struct mwifiex_private *priv = NULL;
        int i;
 
-       if (down_interruptible(sem))
+       if (down_trylock(sem))
                goto exit_sem_err;
 
        if (!adapter)
index a159fbe..0207af0 100644 (file)
 #include <linux/idr.h>
 #include <linux/inetdevice.h>
 #include <linux/devcoredump.h>
+#include <linux/err.h>
+#include <linux/gpio.h>
+#include <linux/gfp.h>
+#include <linux/interrupt.h>
+#include <linux/io.h>
+#include <linux/of_gpio.h>
+#include <linux/of_platform.h>
+#include <linux/platform_device.h>
+#include <linux/pm_runtime.h>
+#include <linux/slab.h>
+#include <linux/of_irq.h>
 
 #include "decl.h"
 #include "ioctl.h"
@@ -100,8 +111,8 @@ enum {
 #define SCAN_BEACON_ENTRY_PAD                  6
 
 #define MWIFIEX_PASSIVE_SCAN_CHAN_TIME 110
-#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME  30
-#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME        30
+#define MWIFIEX_ACTIVE_SCAN_CHAN_TIME  40
+#define MWIFIEX_SPECIFIC_SCAN_CHAN_TIME        40
 #define MWIFIEX_DEF_SCAN_CHAN_GAP_TIME  50
 
 #define SCAN_RSSI(RSSI)                                        (0x100 - ((u8)(RSSI)))
@@ -1042,9 +1053,8 @@ int mwifiex_alloc_cmd_buffer(struct mwifiex_adapter *adapter);
 int mwifiex_free_cmd_buffer(struct mwifiex_adapter *adapter);
 void mwifiex_cancel_all_pending_cmd(struct mwifiex_adapter *adapter);
 void mwifiex_cancel_pending_ioctl(struct mwifiex_adapter *adapter);
+void mwifiex_cancel_pending_scan_cmd(struct mwifiex_adapter *adapter);
 
-void mwifiex_insert_cmd_to_free_q(struct mwifiex_adapter *adapter,
-                                 struct cmd_ctrl_node *cmd_node);
 void mwifiex_recycle_cmd_node(struct mwifiex_adapter *adapter,
                              struct cmd_ctrl_node *cmd_node);
 
index edf8b07..0c7937e 100644 (file)
@@ -2811,6 +2811,7 @@ static int mwifiex_pcie_request_irq(struct mwifiex_adapter *adapter)
 static void mwifiex_pcie_get_fw_name(struct mwifiex_adapter *adapter)
 {
        int revision_id = 0;
+       int version;
        struct pcie_service_card *card = adapter->card;
 
        switch (card->dev->device) {
@@ -2829,18 +2830,34 @@ static void mwifiex_pcie_get_fw_name(struct mwifiex_adapter *adapter)
                        strcpy(adapter->fw_name, PCIE8897_B0_FW_NAME);
                        break;
                default:
+                       strcpy(adapter->fw_name, PCIE8897_DEFAULT_FW_NAME);
+
                        break;
                }
+               break;
        case PCIE_DEVICE_ID_MARVELL_88W8997:
                mwifiex_read_reg(adapter, 0x0c48, &revision_id);
+               mwifiex_read_reg(adapter, 0x0cd0, &version);
+               version &= 0x7;
                switch (revision_id) {
                case PCIE8997_V2:
-                       strcpy(adapter->fw_name, PCIE8997_FW_NAME_V2);
+                       if (version == CHIP_VER_PCIEUSB)
+                               strcpy(adapter->fw_name,
+                                      PCIEUSB8997_FW_NAME_V2);
+                       else
+                               strcpy(adapter->fw_name,
+                                      PCIEUART8997_FW_NAME_V2);
                        break;
                case PCIE8997_Z:
-                       strcpy(adapter->fw_name, PCIE8997_FW_NAME_Z);
+                       if (version == CHIP_VER_PCIEUSB)
+                               strcpy(adapter->fw_name,
+                                      PCIEUSB8997_FW_NAME_Z);
+                       else
+                               strcpy(adapter->fw_name,
+                                      PCIEUART8997_FW_NAME_Z);
                        break;
                default:
+                       strcpy(adapter->fw_name, PCIE8997_DEFAULT_FW_NAME);
                        break;
                }
        default:
index cc7a5df..5770b43 100644 (file)
 #include    "main.h"
 
 #define PCIE8766_DEFAULT_FW_NAME "mrvl/pcie8766_uapsta.bin"
+#define PCIE8897_DEFAULT_FW_NAME "mrvl/pcie8897_uapsta.bin"
 #define PCIE8897_A0_FW_NAME "mrvl/pcie8897_uapsta_a0.bin"
 #define PCIE8897_B0_FW_NAME "mrvl/pcie8897_uapsta.bin"
-#define PCIE8997_FW_NAME_Z "mrvl/pcieusb8997_combo.bin"
-#define PCIE8997_FW_NAME_V2 "mrvl/pcieusb8997_combo_v2.bin"
+#define PCIE8997_DEFAULT_FW_NAME "mrvl/pcieuart8997_combo_v2.bin"
+#define PCIEUART8997_FW_NAME_Z "mrvl/pcieuart8997_combo.bin"
+#define PCIEUART8997_FW_NAME_V2 "mrvl/pcieuart8997_combo_v2.bin"
+#define PCIEUSB8997_FW_NAME_Z "mrvl/pcieusb8997_combo.bin"
+#define PCIEUSB8997_FW_NAME_V2 "mrvl/pcieusb8997_combo_v2.bin"
 
 #define PCIE_VENDOR_ID_MARVELL              (0x11ab)
 #define PCIE_VENDOR_ID_V2_MARVELL           (0x1b4b)
@@ -45,6 +49,7 @@
 #define PCIE8897_B0    0x1200
 #define PCIE8997_Z     0x0
 #define PCIE8997_V2    0x471
+#define CHIP_VER_PCIEUSB       0x2
 
 /* Constants for Buffer Descriptor (BD) rings */
 #define MWIFIEX_MAX_TXRX_BD                    0x20
index 624b0a9..bc5e52c 100644 (file)
@@ -76,6 +76,39 @@ static u8 mwifiex_rsn_oui[CIPHER_SUITE_MAX][4] = {
        { 0x00, 0x0f, 0xac, 0x04 },     /* AES  */
 };
 
+static void
+_dbg_security_flags(int log_level, const char *func, const char *desc,
+                   struct mwifiex_private *priv,
+                   struct mwifiex_bssdescriptor *bss_desc)
+{
+       _mwifiex_dbg(priv->adapter, log_level,
+                    "info: %s: %s:\twpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\tEncMode=%#x privacy=%#x\n",
+                    func, desc,
+                    bss_desc->bcn_wpa_ie ?
+                    bss_desc->bcn_wpa_ie->vend_hdr.element_id : 0,
+                    bss_desc->bcn_rsn_ie ?
+                    bss_desc->bcn_rsn_ie->ieee_hdr.element_id : 0,
+                    priv->sec_info.wep_enabled ? "e" : "d",
+                    priv->sec_info.wpa_enabled ? "e" : "d",
+                    priv->sec_info.wpa2_enabled ? "e" : "d",
+                    priv->sec_info.encryption_mode,
+                    bss_desc->privacy);
+}
+#define dbg_security_flags(mask, desc, priv, bss_desc) \
+       _dbg_security_flags(MWIFIEX_DBG_##mask, desc, __func__, priv, bss_desc)
+
+static bool
+has_ieee_hdr(struct ieee_types_generic *ie, u8 key)
+{
+       return (ie && ie->ieee_hdr.element_id == key);
+}
+
+static bool
+has_vendor_hdr(struct ieee_types_vendor_specific *ie, u8 key)
+{
+       return (ie && ie->vend_hdr.element_id == key);
+}
+
 /*
  * This function parses a given IE for a given OUI.
  *
@@ -121,8 +154,7 @@ mwifiex_is_rsn_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
        struct ie_body *iebody;
        u8 ret = MWIFIEX_OUI_NOT_PRESENT;
 
-       if (((bss_desc->bcn_rsn_ie) && ((*(bss_desc->bcn_rsn_ie)).
-                                       ieee_hdr.element_id == WLAN_EID_RSN))) {
+       if (has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) {
                iebody = (struct ie_body *)
                         (((u8 *) bss_desc->bcn_rsn_ie->data) +
                          RSN_GTK_OUI_OFFSET);
@@ -148,9 +180,7 @@ mwifiex_is_wpa_oui_present(struct mwifiex_bssdescriptor *bss_desc, u32 cipher)
        struct ie_body *iebody;
        u8 ret = MWIFIEX_OUI_NOT_PRESENT;
 
-       if (((bss_desc->bcn_wpa_ie) &&
-            ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id ==
-             WLAN_EID_VENDOR_SPECIFIC))) {
+       if (has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)) {
                iebody = (struct ie_body *) bss_desc->bcn_wpa_ie->data;
                oui = &mwifiex_wpa_oui[cipher][0];
                ret = mwifiex_search_oui_in_ie(iebody, oui);
@@ -180,11 +210,8 @@ mwifiex_is_bss_wapi(struct mwifiex_private *priv,
                    struct mwifiex_bssdescriptor *bss_desc)
 {
        if (priv->sec_info.wapi_enabled &&
-           (bss_desc->bcn_wapi_ie &&
-            ((*(bss_desc->bcn_wapi_ie)).ieee_hdr.element_id ==
-                       WLAN_EID_BSS_AC_ACCESS_DELAY))) {
+           has_ieee_hdr(bss_desc->bcn_wapi_ie, WLAN_EID_BSS_AC_ACCESS_DELAY))
                return true;
-       }
        return false;
 }
 
@@ -197,12 +224,9 @@ mwifiex_is_bss_no_sec(struct mwifiex_private *priv,
                      struct mwifiex_bssdescriptor *bss_desc)
 {
        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
-           !priv->sec_info.wpa2_enabled && ((!bss_desc->bcn_wpa_ie) ||
-               ((*(bss_desc->bcn_wpa_ie)).vend_hdr.element_id !=
-                WLAN_EID_VENDOR_SPECIFIC)) &&
-           ((!bss_desc->bcn_rsn_ie) ||
-               ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id !=
-                WLAN_EID_RSN)) &&
+           !priv->sec_info.wpa2_enabled &&
+           !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) &&
+           !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) &&
            !priv->sec_info.encryption_mode && !bss_desc->privacy) {
                return true;
        }
@@ -233,29 +257,14 @@ mwifiex_is_bss_wpa(struct mwifiex_private *priv,
                   struct mwifiex_bssdescriptor *bss_desc)
 {
        if (!priv->sec_info.wep_enabled && priv->sec_info.wpa_enabled &&
-           !priv->sec_info.wpa2_enabled && ((bss_desc->bcn_wpa_ie) &&
-           ((*(bss_desc->bcn_wpa_ie)).
-            vend_hdr.element_id == WLAN_EID_VENDOR_SPECIFIC))
+           !priv->sec_info.wpa2_enabled &&
+           has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC)
           /*
            * Privacy bit may NOT be set in some APs like
            * LinkSys WRT54G && bss_desc->privacy
            */
         ) {
-               mwifiex_dbg(priv->adapter, INFO,
-                           "info: %s: WPA:\t"
-                           "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\t"
-                           "EncMode=%#x privacy=%#x\n", __func__,
-                           (bss_desc->bcn_wpa_ie) ?
-                           (*bss_desc->bcn_wpa_ie).
-                           vend_hdr.element_id : 0,
-                           (bss_desc->bcn_rsn_ie) ?
-                           (*bss_desc->bcn_rsn_ie).
-                           ieee_hdr.element_id : 0,
-                           (priv->sec_info.wep_enabled) ? "e" : "d",
-                           (priv->sec_info.wpa_enabled) ? "e" : "d",
-                           (priv->sec_info.wpa2_enabled) ? "e" : "d",
-                           priv->sec_info.encryption_mode,
-                           bss_desc->privacy);
+               dbg_security_flags(INFO, "WPA", priv, bss_desc);
                return true;
        }
        return false;
@@ -269,30 +278,14 @@ static bool
 mwifiex_is_bss_wpa2(struct mwifiex_private *priv,
                    struct mwifiex_bssdescriptor *bss_desc)
 {
-       if (!priv->sec_info.wep_enabled &&
-           !priv->sec_info.wpa_enabled &&
+       if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
            priv->sec_info.wpa2_enabled &&
-           ((bss_desc->bcn_rsn_ie) &&
-            ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id == WLAN_EID_RSN))) {
+           has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN)) {
                /*
                 * Privacy bit may NOT be set in some APs like
                 * LinkSys WRT54G && bss_desc->privacy
                 */
-               mwifiex_dbg(priv->adapter, INFO,
-                           "info: %s: WPA2:\t"
-                           "wpa_ie=%#x wpa2_ie=%#x WEP=%s WPA=%s WPA2=%s\t"
-                           "EncMode=%#x privacy=%#x\n", __func__,
-                           (bss_desc->bcn_wpa_ie) ?
-                           (*bss_desc->bcn_wpa_ie).
-                           vend_hdr.element_id : 0,
-                           (bss_desc->bcn_rsn_ie) ?
-                           (*bss_desc->bcn_rsn_ie).
-                           ieee_hdr.element_id : 0,
-                           (priv->sec_info.wep_enabled) ? "e" : "d",
-                           (priv->sec_info.wpa_enabled) ? "e" : "d",
-                           (priv->sec_info.wpa2_enabled) ? "e" : "d",
-                           priv->sec_info.encryption_mode,
-                           bss_desc->privacy);
+               dbg_security_flags(INFO, "WAP2", priv, bss_desc);
                return true;
        }
        return false;
@@ -308,11 +301,8 @@ mwifiex_is_bss_adhoc_aes(struct mwifiex_private *priv,
 {
        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
            !priv->sec_info.wpa2_enabled &&
-           ((!bss_desc->bcn_wpa_ie) ||
-            ((*(bss_desc->bcn_wpa_ie)).
-             vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) &&
-           ((!bss_desc->bcn_rsn_ie) ||
-            ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) &&
+           !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) &&
+           !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) &&
            !priv->sec_info.encryption_mode && bss_desc->privacy) {
                return true;
        }
@@ -329,25 +319,10 @@ mwifiex_is_bss_dynamic_wep(struct mwifiex_private *priv,
 {
        if (!priv->sec_info.wep_enabled && !priv->sec_info.wpa_enabled &&
            !priv->sec_info.wpa2_enabled &&
-           ((!bss_desc->bcn_wpa_ie) ||
-            ((*(bss_desc->bcn_wpa_ie)).
-             vend_hdr.element_id != WLAN_EID_VENDOR_SPECIFIC)) &&
-           ((!bss_desc->bcn_rsn_ie) ||
-            ((*(bss_desc->bcn_rsn_ie)).ieee_hdr.element_id != WLAN_EID_RSN)) &&
+           !has_vendor_hdr(bss_desc->bcn_wpa_ie, WLAN_EID_VENDOR_SPECIFIC) &&
+           !has_ieee_hdr(bss_desc->bcn_rsn_ie, WLAN_EID_RSN) &&
            priv->sec_info.encryption_mode && bss_desc->privacy) {
-               mwifiex_dbg(priv->adapter, INFO,
-                           "info: %s: dynamic\t"
-                           "WEP: wpa_ie=%#x wpa2_ie=%#x\t"
-                           "EncMode=%#x privacy=%#x\n",
-                           __func__,
-                           (bss_desc->bcn_wpa_ie) ?
-                           (*bss_desc->bcn_wpa_ie).
-                           vend_hdr.element_id : 0,
-                           (bss_desc->bcn_rsn_ie) ?
-                           (*bss_desc->bcn_rsn_ie).
-                           ieee_hdr.element_id : 0,
-                           priv->sec_info.encryption_mode,
-                           bss_desc->privacy);
+               dbg_security_flags(INFO, "dynamic", priv, bss_desc);
                return true;
        }
        return false;
@@ -460,18 +435,7 @@ mwifiex_is_network_compatible(struct mwifiex_private *priv,
                }
 
                /* Security doesn't match */
-               mwifiex_dbg(adapter, ERROR,
-                           "info: %s: failed: wpa_ie=%#x wpa2_ie=%#x WEP=%s\t"
-                           "WPA=%s WPA2=%s EncMode=%#x privacy=%#x\n",
-                           __func__,
-                           (bss_desc->bcn_wpa_ie) ?
-                           (*bss_desc->bcn_wpa_ie).vend_hdr.element_id : 0,
-                           (bss_desc->bcn_rsn_ie) ?
-                           (*bss_desc->bcn_rsn_ie).ieee_hdr.element_id : 0,
-                           (priv->sec_info.wep_enabled) ? "e" : "d",
-                           (priv->sec_info.wpa_enabled) ? "e" : "d",
-                           (priv->sec_info.wpa2_enabled) ? "e" : "d",
-                           priv->sec_info.encryption_mode, bss_desc->privacy);
+               dbg_security_flags(ERROR, "failed", priv, bss_desc);
                return -1;
        }
 
@@ -534,11 +498,13 @@ mwifiex_scan_create_channel_list(struct mwifiex_private *priv,
                                        &= ~MWIFIEX_PASSIVE_SCAN;
                        scan_chan_list[chan_idx].chan_number =
                                                        (u32) ch->hw_value;
+
+                       scan_chan_list[chan_idx].chan_scan_mode_bitmap
+                                       |= MWIFIEX_DISABLE_CHAN_FILT;
+
                        if (filtered_scan) {
                                scan_chan_list[chan_idx].max_scan_time =
                                cpu_to_le16(adapter->specific_scan_time);
-                               scan_chan_list[chan_idx].chan_scan_mode_bitmap
-                                       |= MWIFIEX_DISABLE_CHAN_FILT;
                        }
                        chan_idx++;
                }
@@ -655,8 +621,6 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
        int ret = 0;
        struct mwifiex_chan_scan_param_set *tmp_chan_list;
        struct mwifiex_chan_scan_param_set *start_chan;
-       struct cmd_ctrl_node *cmd_node, *tmp_node;
-       unsigned long flags;
        u32 tlv_idx, rates_size, cmd_no;
        u32 total_scan_time;
        u32 done_early;
@@ -813,16 +777,7 @@ mwifiex_scan_channel_list(struct mwifiex_private *priv,
                            sizeof(struct mwifiex_ie_types_header) + rates_size;
 
                if (ret) {
-                       spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
-                       list_for_each_entry_safe(cmd_node, tmp_node,
-                                                &adapter->scan_pending_q,
-                                                list) {
-                               list_del(&cmd_node->list);
-                               cmd_node->wait_q_enabled = false;
-                               mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
-                       }
-                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
-                                              flags);
+                       mwifiex_cancel_pending_scan_cmd(adapter);
                        break;
                }
        }
@@ -912,14 +867,11 @@ mwifiex_config_scan(struct mwifiex_private *priv,
                /* Set the BSS type scan filter, use Adapter setting if
                   unset */
                scan_cfg_out->bss_mode =
-                       (user_scan_in->bss_mode ? (u8) user_scan_in->
-                        bss_mode : (u8) adapter->scan_mode);
+                       (u8)(user_scan_in->bss_mode ?: adapter->scan_mode);
 
                /* Set the number of probes to send, use Adapter setting
                   if unset */
-               num_probes =
-                       (user_scan_in->num_probes ? user_scan_in->
-                        num_probes : adapter->scan_probes);
+               num_probes = user_scan_in->num_probes ?: adapter->scan_probes;
 
                /*
                 * Set the BSSID filter to the incoming configuration,
@@ -1094,28 +1046,24 @@ mwifiex_config_scan(struct mwifiex_private *priv,
                     chan_idx++) {
 
                        channel = user_scan_in->chan_list[chan_idx].chan_number;
-                       (scan_chan_list + chan_idx)->chan_number = channel;
+                       scan_chan_list[chan_idx].chan_number = channel;
 
                        radio_type =
                                user_scan_in->chan_list[chan_idx].radio_type;
-                       (scan_chan_list + chan_idx)->radio_type = radio_type;
+                       scan_chan_list[chan_idx].radio_type = radio_type;
 
                        scan_type = user_scan_in->chan_list[chan_idx].scan_type;
 
                        if (scan_type == MWIFIEX_SCAN_TYPE_PASSIVE)
-                               (scan_chan_list +
-                                chan_idx)->chan_scan_mode_bitmap
+                               scan_chan_list[chan_idx].chan_scan_mode_bitmap
                                        |= (MWIFIEX_PASSIVE_SCAN |
                                            MWIFIEX_HIDDEN_SSID_REPORT);
                        else
-                               (scan_chan_list +
-                                chan_idx)->chan_scan_mode_bitmap
+                               scan_chan_list[chan_idx].chan_scan_mode_bitmap
                                        &= ~MWIFIEX_PASSIVE_SCAN;
 
-                       if (*filtered_scan)
-                               (scan_chan_list +
-                                chan_idx)->chan_scan_mode_bitmap
-                                       |= MWIFIEX_DISABLE_CHAN_FILT;
+                       scan_chan_list[chan_idx].chan_scan_mode_bitmap
+                               |= MWIFIEX_DISABLE_CHAN_FILT;
 
                        if (user_scan_in->chan_list[chan_idx].scan_time) {
                                scan_dur = (u16) user_scan_in->
@@ -1129,9 +1077,9 @@ mwifiex_config_scan(struct mwifiex_private *priv,
                                        scan_dur = adapter->active_scan_time;
                        }
 
-                       (scan_chan_list + chan_idx)->min_scan_time =
+                       scan_chan_list[chan_idx].min_scan_time =
                                cpu_to_le16(scan_dur);
-                       (scan_chan_list + chan_idx)->max_scan_time =
+                       scan_chan_list[chan_idx].max_scan_time =
                                cpu_to_le16(scan_dur);
                }
 
@@ -1991,12 +1939,13 @@ mwifiex_active_scan_req_for_passive_chan(struct mwifiex_private *priv)
 static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
 {
        struct mwifiex_adapter *adapter = priv->adapter;
-       struct cmd_ctrl_node *cmd_node, *tmp_node;
+       struct cmd_ctrl_node *cmd_node;
        unsigned long flags;
 
        spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
        if (list_empty(&adapter->scan_pending_q)) {
                spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+
                spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
                adapter->scan_processing = false;
                spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
@@ -2018,13 +1967,10 @@ static void mwifiex_check_next_scan_command(struct mwifiex_private *priv)
                }
        } else if ((priv->scan_aborting && !priv->scan_request) ||
                   priv->scan_block) {
-               list_for_each_entry_safe(cmd_node, tmp_node,
-                                        &adapter->scan_pending_q, list) {
-                       list_del(&cmd_node->list);
-                       mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
-               }
                spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
 
+               mwifiex_cancel_pending_scan_cmd(adapter);
+
                spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
                adapter->scan_processing = false;
                spin_unlock_irqrestore(&adapter->mwifiex_cmd_lock, flags);
index a0aec3e..099722e 100644 (file)
@@ -73,6 +73,66 @@ static struct memory_type_mapping mem_type_mapping_tbl[] = {
        {"EXTLAST", NULL, 0, 0xFE},
 };
 
+static const struct of_device_id mwifiex_sdio_of_match_table[] = {
+       { .compatible = "marvell,sd8897" },
+       { .compatible = "marvell,sd8997" },
+       { }
+};
+
+static irqreturn_t mwifiex_wake_irq_wifi(int irq, void *priv)
+{
+       struct mwifiex_plt_wake_cfg *cfg = priv;
+
+       if (cfg->irq_wifi >= 0) {
+               pr_info("%s: wake by wifi", __func__);
+               cfg->wake_by_wifi = true;
+               disable_irq_nosync(irq);
+       }
+
+       return IRQ_HANDLED;
+}
+
+/* This function parse device tree node using mmc subnode devicetree API.
+ * The device node is saved in card->plt_of_node.
+ * if the device tree node exist and include interrupts attributes, this
+ * function will also request platform specific wakeup interrupt.
+ */
+static int mwifiex_sdio_probe_of(struct device *dev, struct sdio_mmc_card *card)
+{
+       struct mwifiex_plt_wake_cfg *cfg;
+       int ret;
+
+       if (!dev->of_node ||
+           !of_match_node(mwifiex_sdio_of_match_table, dev->of_node)) {
+               pr_err("sdio platform data not available");
+               return -1;
+       }
+
+       card->plt_of_node = dev->of_node;
+       card->plt_wake_cfg = devm_kzalloc(dev, sizeof(*card->plt_wake_cfg),
+                                         GFP_KERNEL);
+       cfg = card->plt_wake_cfg;
+       if (cfg && card->plt_of_node) {
+               cfg->irq_wifi = irq_of_parse_and_map(card->plt_of_node, 0);
+               if (!cfg->irq_wifi) {
+                       dev_err(dev, "fail to parse irq_wifi from device tree");
+               } else {
+                       ret = devm_request_irq(dev, cfg->irq_wifi,
+                                              mwifiex_wake_irq_wifi,
+                                              IRQF_TRIGGER_LOW,
+                                              "wifi_wake", cfg);
+                       if (ret) {
+                               dev_err(dev,
+                                       "Failed to request irq_wifi %d (%d)\n",
+                                       cfg->irq_wifi, ret);
+                       }
+                       disable_irq(cfg->irq_wifi);
+               }
+       }
+
+       return 0;
+}
+
 /*
  * SDIO probe.
  *
@@ -127,6 +187,9 @@ mwifiex_sdio_probe(struct sdio_func *func, const struct sdio_device_id *id)
                return -EIO;
        }
 
+       /* device tree node parsing and platform specific configuration*/
+       mwifiex_sdio_probe_of(&func->dev, card);
+
        if (mwifiex_add_card(card, &add_remove_card_sem, &sdio_ops,
                             MWIFIEX_SDIO)) {
                pr_err("%s: add card failed\n", __func__);
@@ -183,6 +246,13 @@ static int mwifiex_sdio_resume(struct device *dev)
        mwifiex_cancel_hs(mwifiex_get_priv(adapter, MWIFIEX_BSS_ROLE_STA),
                          MWIFIEX_SYNC_CMD);
 
+       /* Disable platform specific wakeup interrupt */
+       if (card->plt_wake_cfg && card->plt_wake_cfg->irq_wifi >= 0) {
+               disable_irq_wake(card->plt_wake_cfg->irq_wifi);
+               if (!card->plt_wake_cfg->wake_by_wifi)
+                       disable_irq(card->plt_wake_cfg->irq_wifi);
+       }
+
        return 0;
 }
 
@@ -262,6 +332,13 @@ static int mwifiex_sdio_suspend(struct device *dev)
 
        adapter = card->adapter;
 
+       /* Enable platform specific wakeup interrupt */
+       if (card->plt_wake_cfg && card->plt_wake_cfg->irq_wifi >= 0) {
+               card->plt_wake_cfg->wake_by_wifi = false;
+               enable_irq(card->plt_wake_cfg->irq_wifi);
+               enable_irq_wake(card->plt_wake_cfg->irq_wifi);
+       }
+
        /* Enable the Host Sleep */
        if (!mwifiex_enable_hs(adapter)) {
                mwifiex_dbg(adapter, ERROR,
@@ -1026,13 +1103,12 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                offset += txlen;
        } while (true);
 
-       sdio_release_host(card->func);
-
        mwifiex_dbg(adapter, MSG,
                    "info: FW download over, size %d bytes\n", offset);
 
        ret = 0;
 done:
+       sdio_release_host(card->func);
        kfree(fwbuf);
        return ret;
 }
index b9fbc5c..db837f1 100644 (file)
        a->mpa_rx.start_port = 0;                                       \
 } while (0)
 
+struct mwifiex_plt_wake_cfg {
+       int irq_wifi;
+       bool wake_by_wifi;
+};
+
 /* data structure for SDIO MPA TX */
 struct mwifiex_sdio_mpa_tx {
        /* multiport tx aggregation buffer pointer */
@@ -237,6 +242,8 @@ struct mwifiex_sdio_card_reg {
 struct sdio_mmc_card {
        struct sdio_func *func;
        struct mwifiex_adapter *adapter;
+       struct device_node *plt_of_node;
+       struct mwifiex_plt_wake_cfg *plt_wake_cfg;
 
        const char *firmware;
        const struct mwifiex_sdio_card_reg *reg;
index 8cb895b..e436574 100644 (file)
@@ -2162,6 +2162,7 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
        enum state_11d_t state_11d;
        struct mwifiex_ds_11n_tx_cfg tx_cfg;
        u8 sdio_sp_rx_aggr_enable;
+       int data;
 
        if (first_sta) {
                if (priv->adapter->iface_type == MWIFIEX_PCIE) {
@@ -2182,9 +2183,16 @@ int mwifiex_sta_init_cmd(struct mwifiex_private *priv, u8 first_sta, bool init)
                 * The cal-data can be read from device tree and/or
                 * a configuration file and downloaded to firmware.
                 */
-               adapter->dt_node =
-                               of_find_node_by_name(NULL, "marvell_cfgdata");
-               if (adapter->dt_node) {
+               if (priv->adapter->iface_type == MWIFIEX_SDIO &&
+                   adapter->dev->of_node) {
+                       adapter->dt_node = adapter->dev->of_node;
+                       if (of_property_read_u32(adapter->dt_node,
+                                                "marvell,wakeup-pin",
+                                                &data) == 0) {
+                               pr_debug("Wakeup pin = 0x%x\n", data);
+                               adapter->hs_cfg.gpio = data;
+                       }
+
                        ret = mwifiex_dnld_dt_cfgdata(priv, adapter->dt_node,
                                                      "marvell,caldata");
                        if (ret)
index 434b977..d18c797 100644 (file)
@@ -44,7 +44,6 @@ static void
 mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
                              struct host_cmd_ds_command *resp)
 {
-       struct cmd_ctrl_node *cmd_node = NULL, *tmp_node;
        struct mwifiex_adapter *adapter = priv->adapter;
        struct host_cmd_ds_802_11_ps_mode_enh *pm;
        unsigned long flags;
@@ -71,17 +70,7 @@ mwifiex_process_cmdresp_error(struct mwifiex_private *priv,
                break;
        case HostCmd_CMD_802_11_SCAN:
        case HostCmd_CMD_802_11_SCAN_EXT:
-               /* Cancel all pending scan command */
-               spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
-               list_for_each_entry_safe(cmd_node, tmp_node,
-                                        &adapter->scan_pending_q, list) {
-                       list_del(&cmd_node->list);
-                       spin_unlock_irqrestore(&adapter->scan_pending_q_lock,
-                                              flags);
-                       mwifiex_insert_cmd_to_free_q(adapter, cmd_node);
-                       spin_lock_irqsave(&adapter->scan_pending_q_lock, flags);
-               }
-               spin_unlock_irqrestore(&adapter->scan_pending_q_lock, flags);
+               mwifiex_cancel_pending_scan_cmd(adapter);
 
                spin_lock_irqsave(&adapter->mwifiex_cmd_lock, flags);
                adapter->scan_processing = false;
index d8de432..8e08626 100644 (file)
@@ -146,6 +146,7 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
        size_t beacon_ie_len;
        struct mwifiex_bss_priv *bss_priv = (void *)bss->priv;
        const struct cfg80211_bss_ies *ies;
+       int ret;
 
        rcu_read_lock();
        ies = rcu_dereference(bss->ies);
@@ -189,7 +190,48 @@ int mwifiex_fill_new_bss_desc(struct mwifiex_private *priv,
        if (bss_desc->cap_info_bitmap & WLAN_CAPABILITY_SPECTRUM_MGMT)
                bss_desc->sensed_11h = true;
 
-       return mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
+       ret = mwifiex_update_bss_desc_with_ie(priv->adapter, bss_desc);
+       if (ret)
+               return ret;
+
+       /* Update HT40 capability based on current channel information */
+       if (bss_desc->bcn_ht_oper && bss_desc->bcn_ht_cap) {
+               u8 ht_param = bss_desc->bcn_ht_oper->ht_param;
+               u8 radio = mwifiex_band_to_radio_type(bss_desc->bss_band);
+               struct ieee80211_supported_band *sband =
+                                               priv->wdev.wiphy->bands[radio];
+               int freq = ieee80211_channel_to_frequency(bss_desc->channel,
+                                                         radio);
+               struct ieee80211_channel *chan =
+                       ieee80211_get_channel(priv->adapter->wiphy, freq);
+
+               switch (ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+               case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+                       if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS) {
+                               sband->ht_cap.cap &=
+                                       ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                               sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
+                       } else {
+                               sband->ht_cap.cap |=
+                                       IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                                       IEEE80211_HT_CAP_SGI_40;
+                       }
+                       break;
+               case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+                       if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS) {
+                               sband->ht_cap.cap &=
+                                       ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+                               sband->ht_cap.cap &= ~IEEE80211_HT_CAP_SGI_40;
+                       } else {
+                               sband->ht_cap.cap |=
+                                       IEEE80211_HT_CAP_SUP_WIDTH_20_40 |
+                                       IEEE80211_HT_CAP_SGI_40;
+                       }
+                       break;
+               }
+       }
+
+       return 0;
 }
 
 void mwifiex_dnld_txpwr_table(struct mwifiex_private *priv)
index bf6182b..abdd0cf 100644 (file)
@@ -297,6 +297,13 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
                goto done;
 
        mwifiex_set_trans_start(priv->netdev);
+
+       if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
+               atomic_dec_return(&adapter->pending_bridged_pkts);
+
+       if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
+               goto done;
+
        if (!status) {
                priv->stats.tx_packets++;
                priv->stats.tx_bytes += tx_info->pkt_len;
@@ -306,12 +313,6 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
                priv->stats.tx_errors++;
        }
 
-       if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
-               atomic_dec_return(&adapter->pending_bridged_pkts);
-
-       if (tx_info->flags & MWIFIEX_BUF_FLAG_AGGR_PKT)
-               goto done;
-
        if (aggr)
                /* For skb_aggr, do not wake up tx queue */
                goto done;
index c95b61d..666e91a 100644 (file)
@@ -102,6 +102,7 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
        int hdr_chop;
        struct ethhdr *p_ethhdr;
        struct mwifiex_sta_node *src_node;
+       int index;
 
        uap_rx_pd = (struct uap_rxpd *)(skb->data);
        rx_pkt_hdr = (void *)uap_rx_pd + le16_to_cpu(uap_rx_pd->rx_pkt_offset);
@@ -208,6 +209,9 @@ static void mwifiex_uap_queue_bridged_pkt(struct mwifiex_private *priv,
        }
 
        __net_timestamp(skb);
+
+       index = mwifiex_1d_to_wmm_queue[skb->priority];
+       atomic_inc(&priv->wmm_tx_pending[index]);
        mwifiex_wmm_add_buf_txqueue(priv, skb);
        atomic_inc(&adapter->tx_pending);
        atomic_inc(&adapter->pending_bridged_pkts);
index 0510861..0857575 100644 (file)
@@ -995,7 +995,8 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
 {
        int ret = 0;
        u8 *firmware = fw->fw_buf, *recv_buff;
-       u32 retries = USB8XXX_FW_MAX_RETRY, dlen;
+       u32 retries = USB8XXX_FW_MAX_RETRY + 1;
+       u32 dlen;
        u32 fw_seqnum = 0, tlen = 0, dnld_cmd = 0;
        struct fw_data *fwdata;
        struct fw_sync_header sync_fw;
@@ -1017,8 +1018,10 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
 
        /* Allocate memory for receive */
        recv_buff = kzalloc(FW_DNLD_RX_BUF_SIZE, GFP_KERNEL);
-       if (!recv_buff)
+       if (!recv_buff) {
+               ret = -ENOMEM;
                goto cleanup;
+       }
 
        do {
                /* Send pseudo data to check winner status first */
@@ -1041,7 +1044,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                }
 
                /* If the send/receive fails or CRC occurs then retry */
-               while (retries--) {
+               while (--retries) {
                        u8 *buf = (u8 *)fwdata;
                        u32 len = FW_DATA_XMIT_SIZE;
 
@@ -1101,7 +1104,7 @@ static int mwifiex_prog_fw_w_helper(struct mwifiex_adapter *adapter,
                                continue;
                        }
 
-                       retries = USB8XXX_FW_MAX_RETRY;
+                       retries = USB8XXX_FW_MAX_RETRY + 1;
                        break;
                }
                fw_seqnum++;
index c36fa4e..bf3f0a3 100644 (file)
@@ -7492,6 +7492,10 @@ static int rt2800_probe_hw_mode(struct rt2x00_dev *rt2x00dev)
        if (!rt2x00_is_usb(rt2x00dev))
                ieee80211_hw_set(rt2x00dev->hw, HOST_BROADCAST_PS_BUFFERING);
 
+       /* Set MFP if HW crypto is disabled. */
+       if (rt2800_hwcrypt_disabled(rt2x00dev))
+               ieee80211_hw_set(rt2x00dev->hw, MFP_CAPABLE);
+
        SET_IEEE80211_DEV(rt2x00dev->hw, rt2x00dev->dev);
        SET_IEEE80211_PERM_ADDR(rt2x00dev->hw,
                                rt2800_eeprom_addr(rt2x00dev,
index ba242d0..e895a84 100644 (file)
@@ -1018,6 +1018,8 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev)
                dma_addr_t *mapping;
                entry = priv->rx_ring + priv->rx_ring_sz*i;
                if (!skb) {
+                       pci_free_consistent(priv->pdev, priv->rx_ring_sz * 32,
+                                       priv->rx_ring, priv->rx_ring_dma);
                        wiphy_err(dev->wiphy, "Cannot allocate RX skb\n");
                        return -ENOMEM;
                }
@@ -1028,6 +1030,8 @@ static int rtl8180_init_rx_ring(struct ieee80211_hw *dev)
 
                if (pci_dma_mapping_error(priv->pdev, *mapping)) {
                        kfree_skb(skb);
+                       pci_free_consistent(priv->pdev, priv->rx_ring_sz * 32,
+                                       priv->rx_ring, priv->rx_ring_dma);
                        wiphy_err(dev->wiphy, "Cannot map DMA for RX skb\n");
                        return -ENOMEM;
                }
index db8433a..f2ce8c9 100644 (file)
@@ -1,7 +1,7 @@
 /*
  * RTL8XXXU mac80211 USB driver
  *
- * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ * Copyright (c) 2014 - 2016 Jes Sorensen <Jes.Sorensen@redhat.com>
  *
  * Portions, notably calibration code:
  * Copyright(c) 2007 - 2011 Realtek Corporation. All rights reserved.
@@ -128,7 +128,7 @@ static struct ieee80211_supported_band rtl8xxxu_supported_band = {
        .n_bitrates = ARRAY_SIZE(rtl8xxxu_rates),
 };
 
-static struct rtl8xxxu_reg8val rtl8723a_mac_init_table[] = {
+static struct rtl8xxxu_reg8val rtl8xxxu_gen1_mac_init_table[] = {
        {0x420, 0x80}, {0x423, 0x00}, {0x430, 0x00}, {0x431, 0x00},
        {0x432, 0x00}, {0x433, 0x01}, {0x434, 0x04}, {0x435, 0x05},
        {0x436, 0x06}, {0x437, 0x07}, {0x438, 0x00}, {0x439, 0x00},
@@ -184,6 +184,104 @@ static struct rtl8xxxu_reg8val rtl8723b_mac_init_table[] = {
        {0xffff, 0xff},
 };
 
+static struct rtl8xxxu_reg8val rtl8192e_mac_init_table[] = {
+       {0x011, 0xeb}, {0x012, 0x07}, {0x014, 0x75}, {0x303, 0xa7},
+       {0x428, 0x0a}, {0x429, 0x10}, {0x430, 0x00}, {0x431, 0x00},
+       {0x432, 0x00}, {0x433, 0x01}, {0x434, 0x04}, {0x435, 0x05},
+       {0x436, 0x07}, {0x437, 0x08}, {0x43c, 0x04}, {0x43d, 0x05},
+       {0x43e, 0x07}, {0x43f, 0x08}, {0x440, 0x5d}, {0x441, 0x01},
+       {0x442, 0x00}, {0x444, 0x10}, {0x445, 0x00}, {0x446, 0x00},
+       {0x447, 0x00}, {0x448, 0x00}, {0x449, 0xf0}, {0x44a, 0x0f},
+       {0x44b, 0x3e}, {0x44c, 0x10}, {0x44d, 0x00}, {0x44e, 0x00},
+       {0x44f, 0x00}, {0x450, 0x00}, {0x451, 0xf0}, {0x452, 0x0f},
+       {0x453, 0x00}, {0x456, 0x5e}, {0x460, 0x66}, {0x461, 0x66},
+       {0x4c8, 0xff}, {0x4c9, 0x08}, {0x4cc, 0xff}, {0x4cd, 0xff},
+       {0x4ce, 0x01}, {0x500, 0x26}, {0x501, 0xa2}, {0x502, 0x2f},
+       {0x503, 0x00}, {0x504, 0x28}, {0x505, 0xa3}, {0x506, 0x5e},
+       {0x507, 0x00}, {0x508, 0x2b}, {0x509, 0xa4}, {0x50a, 0x5e},
+       {0x50b, 0x00}, {0x50c, 0x4f}, {0x50d, 0xa4}, {0x50e, 0x00},
+       {0x50f, 0x00}, {0x512, 0x1c}, {0x514, 0x0a}, {0x516, 0x0a},
+       {0x525, 0x4f}, {0x540, 0x12}, {0x541, 0x64}, {0x550, 0x10},
+       {0x551, 0x10}, {0x559, 0x02}, {0x55c, 0x50}, {0x55d, 0xff},
+       {0x605, 0x30}, {0x608, 0x0e}, {0x609, 0x2a}, {0x620, 0xff},
+       {0x621, 0xff}, {0x622, 0xff}, {0x623, 0xff}, {0x624, 0xff},
+       {0x625, 0xff}, {0x626, 0xff}, {0x627, 0xff}, {0x638, 0x50},
+       {0x63c, 0x0a}, {0x63d, 0x0a}, {0x63e, 0x0e}, {0x63f, 0x0e},
+       {0x640, 0x40}, {0x642, 0x40}, {0x643, 0x00}, {0x652, 0xc8},
+       {0x66e, 0x05}, {0x700, 0x21}, {0x701, 0x43}, {0x702, 0x65},
+       {0x703, 0x87}, {0x708, 0x21}, {0x709, 0x43}, {0x70a, 0x65},
+       {0x70b, 0x87},
+       {0xffff, 0xff},
+};
+
+#ifdef CONFIG_RTL8XXXU_UNTESTED
+static struct rtl8xxxu_power_base rtl8188r_power_base = {
+       .reg_0e00 = 0x06080808,
+       .reg_0e04 = 0x00040406,
+       .reg_0e08 = 0x00000000,
+       .reg_086c = 0x00000000,
+
+       .reg_0e10 = 0x04060608,
+       .reg_0e14 = 0x00020204,
+       .reg_0e18 = 0x04060608,
+       .reg_0e1c = 0x00020204,
+
+       .reg_0830 = 0x06080808,
+       .reg_0834 = 0x00040406,
+       .reg_0838 = 0x00000000,
+       .reg_086c_2 = 0x00000000,
+
+       .reg_083c = 0x04060608,
+       .reg_0848 = 0x00020204,
+       .reg_084c = 0x04060608,
+       .reg_0868 = 0x00020204,
+};
+
+static struct rtl8xxxu_power_base rtl8192c_power_base = {
+       .reg_0e00 = 0x07090c0c,
+       .reg_0e04 = 0x01020405,
+       .reg_0e08 = 0x00000000,
+       .reg_086c = 0x00000000,
+
+       .reg_0e10 = 0x0b0c0c0e,
+       .reg_0e14 = 0x01030506,
+       .reg_0e18 = 0x0b0c0d0e,
+       .reg_0e1c = 0x01030509,
+
+       .reg_0830 = 0x07090c0c,
+       .reg_0834 = 0x01020405,
+       .reg_0838 = 0x00000000,
+       .reg_086c_2 = 0x00000000,
+
+       .reg_083c = 0x0b0c0d0e,
+       .reg_0848 = 0x01030509,
+       .reg_084c = 0x0b0c0d0e,
+       .reg_0868 = 0x01030509,
+};
+#endif
+
+static struct rtl8xxxu_power_base rtl8723a_power_base = {
+       .reg_0e00 = 0x0a0c0c0c,
+       .reg_0e04 = 0x02040608,
+       .reg_0e08 = 0x00000000,
+       .reg_086c = 0x00000000,
+
+       .reg_0e10 = 0x0a0c0d0e,
+       .reg_0e14 = 0x02040608,
+       .reg_0e18 = 0x0a0c0d0e,
+       .reg_0e1c = 0x02040608,
+
+       .reg_0830 = 0x0a0c0c0c,
+       .reg_0834 = 0x02040608,
+       .reg_0838 = 0x00000000,
+       .reg_086c_2 = 0x00000000,
+
+       .reg_083c = 0x0a0c0d0e,
+       .reg_0848 = 0x02040608,
+       .reg_084c = 0x0a0c0d0e,
+       .reg_0868 = 0x02040608,
+};
+
 static struct rtl8xxxu_reg32val rtl8723a_phy_1t_init_table[] = {
        {0x800, 0x80040000}, {0x804, 0x00000003},
        {0x808, 0x0000fc00}, {0x80c, 0x0000000a},
@@ -580,6 +678,138 @@ static struct rtl8xxxu_reg32val rtl8188ru_phy_1t_highpa_table[] = {
        {0xffff, 0xffffffff},
 };
 
+static struct rtl8xxxu_reg32val rtl8192eu_phy_init_table[] = {
+       {0x800, 0x80040000}, {0x804, 0x00000003},
+       {0x808, 0x0000fc00}, {0x80c, 0x0000000a},
+       {0x810, 0x10001331}, {0x814, 0x020c3d10},
+       {0x818, 0x02220385}, {0x81c, 0x00000000},
+       {0x820, 0x01000100}, {0x824, 0x00390204},
+       {0x828, 0x01000100}, {0x82c, 0x00390204},
+       {0x830, 0x32323232}, {0x834, 0x30303030},
+       {0x838, 0x30303030}, {0x83c, 0x30303030},
+       {0x840, 0x00010000}, {0x844, 0x00010000},
+       {0x848, 0x28282828}, {0x84c, 0x28282828},
+       {0x850, 0x00000000}, {0x854, 0x00000000},
+       {0x858, 0x009a009a}, {0x85c, 0x01000014},
+       {0x860, 0x66f60000}, {0x864, 0x061f0000},
+       {0x868, 0x30303030}, {0x86c, 0x30303030},
+       {0x870, 0x00000000}, {0x874, 0x55004200},
+       {0x878, 0x08080808}, {0x87c, 0x00000000},
+       {0x880, 0xb0000c1c}, {0x884, 0x00000001},
+       {0x888, 0x00000000}, {0x88c, 0xcc0000c0},
+       {0x890, 0x00000800}, {0x894, 0xfffffffe},
+       {0x898, 0x40302010}, {0x900, 0x00000000},
+       {0x904, 0x00000023}, {0x908, 0x00000000},
+       {0x90c, 0x81121313}, {0x910, 0x806c0001},
+       {0x914, 0x00000001}, {0x918, 0x00000000},
+       {0x91c, 0x00010000}, {0x924, 0x00000001},
+       {0x928, 0x00000000}, {0x92c, 0x00000000},
+       {0x930, 0x00000000}, {0x934, 0x00000000},
+       {0x938, 0x00000000}, {0x93c, 0x00000000},
+       {0x940, 0x00000000}, {0x944, 0x00000000},
+       {0x94c, 0x00000008}, {0xa00, 0x00d0c7c8},
+       {0xa04, 0x81ff000c}, {0xa08, 0x8c838300},
+       {0xa0c, 0x2e68120f}, {0xa10, 0x95009b78},
+       {0xa14, 0x1114d028}, {0xa18, 0x00881117},
+       {0xa1c, 0x89140f00}, {0xa20, 0x1a1b0000},
+       {0xa24, 0x090e1317}, {0xa28, 0x00000204},
+       {0xa2c, 0x00d30000}, {0xa70, 0x101fff00},
+       {0xa74, 0x00000007}, {0xa78, 0x00000900},
+       {0xa7c, 0x225b0606}, {0xa80, 0x218075b1},
+       {0xb38, 0x00000000}, {0xc00, 0x48071d40},
+       {0xc04, 0x03a05633}, {0xc08, 0x000000e4},
+       {0xc0c, 0x6c6c6c6c}, {0xc10, 0x08800000},
+       {0xc14, 0x40000100}, {0xc18, 0x08800000},
+       {0xc1c, 0x40000100}, {0xc20, 0x00000000},
+       {0xc24, 0x00000000}, {0xc28, 0x00000000},
+       {0xc2c, 0x00000000}, {0xc30, 0x69e9ac47},
+       {0xc34, 0x469652af}, {0xc38, 0x49795994},
+       {0xc3c, 0x0a97971c}, {0xc40, 0x1f7c403f},
+       {0xc44, 0x000100b7}, {0xc48, 0xec020107},
+       {0xc4c, 0x007f037f},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0xc50, 0x00340220},
+#else
+       {0xc50, 0x00340020},
+#endif
+       {0xc54, 0x0080801f},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0xc58, 0x00000220},
+#else
+       {0xc58, 0x00000020},
+#endif
+       {0xc5c, 0x00248492}, {0xc60, 0x00000000},
+       {0xc64, 0x7112848b}, {0xc68, 0x47c00bff},
+       {0xc6c, 0x00000036}, {0xc70, 0x00000600},
+       {0xc74, 0x02013169}, {0xc78, 0x0000001f},
+       {0xc7c, 0x00b91612},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0xc80, 0x2d4000b5},
+#else
+       {0xc80, 0x40000100},
+#endif
+       {0xc84, 0x21f60000},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0xc88, 0x2d4000b5},
+#else
+       {0xc88, 0x40000100},
+#endif
+       {0xc8c, 0xa0e40000}, {0xc90, 0x00121820},
+       {0xc94, 0x00000000}, {0xc98, 0x00121820},
+       {0xc9c, 0x00007f7f}, {0xca0, 0x00000000},
+       {0xca4, 0x000300a0}, {0xca8, 0x00000000},
+       {0xcac, 0x00000000}, {0xcb0, 0x00000000},
+       {0xcb4, 0x00000000}, {0xcb8, 0x00000000},
+       {0xcbc, 0x28000000}, {0xcc0, 0x00000000},
+       {0xcc4, 0x00000000}, {0xcc8, 0x00000000},
+       {0xccc, 0x00000000}, {0xcd0, 0x00000000},
+       {0xcd4, 0x00000000}, {0xcd8, 0x64b22427},
+       {0xcdc, 0x00766932}, {0xce0, 0x00222222},
+       {0xce4, 0x00040000}, {0xce8, 0x77644302},
+       {0xcec, 0x2f97d40c}, {0xd00, 0x00080740},
+       {0xd04, 0x00020403}, {0xd08, 0x0000907f},
+       {0xd0c, 0x20010201}, {0xd10, 0xa0633333},
+       {0xd14, 0x3333bc43}, {0xd18, 0x7a8f5b6b},
+       {0xd1c, 0x0000007f}, {0xd2c, 0xcc979975},
+       {0xd30, 0x00000000}, {0xd34, 0x80608000},
+       {0xd38, 0x00000000}, {0xd3c, 0x00127353},
+       {0xd40, 0x00000000}, {0xd44, 0x00000000},
+       {0xd48, 0x00000000}, {0xd4c, 0x00000000},
+       {0xd50, 0x6437140a}, {0xd54, 0x00000000},
+       {0xd58, 0x00000282}, {0xd5c, 0x30032064},
+       {0xd60, 0x4653de68}, {0xd64, 0x04518a3c},
+       {0xd68, 0x00002101}, {0xd6c, 0x2a201c16},
+       {0xd70, 0x1812362e}, {0xd74, 0x322c2220},
+       {0xd78, 0x000e3c24}, {0xd80, 0x01081008},
+       {0xd84, 0x00000800}, {0xd88, 0xf0b50000},
+       {0xe00, 0x30303030}, {0xe04, 0x30303030},
+       {0xe08, 0x03903030}, {0xe10, 0x30303030},
+       {0xe14, 0x30303030}, {0xe18, 0x30303030},
+       {0xe1c, 0x30303030}, {0xe28, 0x00000000},
+       {0xe30, 0x1000dc1f}, {0xe34, 0x10008c1f},
+       {0xe38, 0x02140102}, {0xe3c, 0x681604c2},
+       {0xe40, 0x01007c00}, {0xe44, 0x01004800},
+       {0xe48, 0xfb000000}, {0xe4c, 0x000028d1},
+       {0xe50, 0x1000dc1f}, {0xe54, 0x10008c1f},
+       {0xe58, 0x02140102}, {0xe5c, 0x28160d05},
+       {0xe60, 0x00000008}, {0xe68, 0x0fc05656},
+       {0xe6c, 0x03c09696}, {0xe70, 0x03c09696},
+       {0xe74, 0x0c005656}, {0xe78, 0x0c005656},
+       {0xe7c, 0x0c005656}, {0xe80, 0x0c005656},
+       {0xe84, 0x03c09696}, {0xe88, 0x0c005656},
+       {0xe8c, 0x03c09696}, {0xed0, 0x03c09696},
+       {0xed4, 0x03c09696}, {0xed8, 0x03c09696},
+       {0xedc, 0x0000d6d6}, {0xee0, 0x0000d6d6},
+       {0xeec, 0x0fc01616}, {0xee4, 0xb0000c1c},
+       {0xee8, 0x00000001}, {0xf14, 0x00000003},
+       {0xf4c, 0x00000000}, {0xf00, 0x00000300},
+       {0xffff, 0xffffffff},
+};
+
 static struct rtl8xxxu_reg32val rtl8xxx_agc_standard_table[] = {
        {0xc78, 0x7b000001}, {0xc78, 0x7b010001},
        {0xc78, 0x7b020001}, {0xc78, 0x7b030001},
@@ -819,6 +1049,144 @@ static struct rtl8xxxu_reg32val rtl8xxx_agc_8723bu_table[] = {
        {0xffff, 0xffffffff}
 };
 
+static struct rtl8xxxu_reg32val rtl8xxx_agc_8192eu_std_table[] = {
+       {0xc78, 0xfb000001}, {0xc78, 0xfb010001},
+       {0xc78, 0xfb020001}, {0xc78, 0xfb030001},
+       {0xc78, 0xfb040001}, {0xc78, 0xfb050001},
+       {0xc78, 0xfa060001}, {0xc78, 0xf9070001},
+       {0xc78, 0xf8080001}, {0xc78, 0xf7090001},
+       {0xc78, 0xf60a0001}, {0xc78, 0xf50b0001},
+       {0xc78, 0xf40c0001}, {0xc78, 0xf30d0001},
+       {0xc78, 0xf20e0001}, {0xc78, 0xf10f0001},
+       {0xc78, 0xf0100001}, {0xc78, 0xef110001},
+       {0xc78, 0xee120001}, {0xc78, 0xed130001},
+       {0xc78, 0xec140001}, {0xc78, 0xeb150001},
+       {0xc78, 0xea160001}, {0xc78, 0xe9170001},
+       {0xc78, 0xe8180001}, {0xc78, 0xe7190001},
+       {0xc78, 0xc81a0001}, {0xc78, 0xc71b0001},
+       {0xc78, 0xc61c0001}, {0xc78, 0x071d0001},
+       {0xc78, 0x061e0001}, {0xc78, 0x051f0001},
+       {0xc78, 0x04200001}, {0xc78, 0x03210001},
+       {0xc78, 0xaa220001}, {0xc78, 0xa9230001},
+       {0xc78, 0xa8240001}, {0xc78, 0xa7250001},
+       {0xc78, 0xa6260001}, {0xc78, 0x85270001},
+       {0xc78, 0x84280001}, {0xc78, 0x83290001},
+       {0xc78, 0x252a0001}, {0xc78, 0x242b0001},
+       {0xc78, 0x232c0001}, {0xc78, 0x222d0001},
+       {0xc78, 0x672e0001}, {0xc78, 0x662f0001},
+       {0xc78, 0x65300001}, {0xc78, 0x64310001},
+       {0xc78, 0x63320001}, {0xc78, 0x62330001},
+       {0xc78, 0x61340001}, {0xc78, 0x45350001},
+       {0xc78, 0x44360001}, {0xc78, 0x43370001},
+       {0xc78, 0x42380001}, {0xc78, 0x41390001},
+       {0xc78, 0x403a0001}, {0xc78, 0x403b0001},
+       {0xc78, 0x403c0001}, {0xc78, 0x403d0001},
+       {0xc78, 0x403e0001}, {0xc78, 0x403f0001},
+       {0xc78, 0xfb400001}, {0xc78, 0xfb410001},
+       {0xc78, 0xfb420001}, {0xc78, 0xfb430001},
+       {0xc78, 0xfb440001}, {0xc78, 0xfb450001},
+       {0xc78, 0xfa460001}, {0xc78, 0xf9470001},
+       {0xc78, 0xf8480001}, {0xc78, 0xf7490001},
+       {0xc78, 0xf64a0001}, {0xc78, 0xf54b0001},
+       {0xc78, 0xf44c0001}, {0xc78, 0xf34d0001},
+       {0xc78, 0xf24e0001}, {0xc78, 0xf14f0001},
+       {0xc78, 0xf0500001}, {0xc78, 0xef510001},
+       {0xc78, 0xee520001}, {0xc78, 0xed530001},
+       {0xc78, 0xec540001}, {0xc78, 0xeb550001},
+       {0xc78, 0xea560001}, {0xc78, 0xe9570001},
+       {0xc78, 0xe8580001}, {0xc78, 0xe7590001},
+       {0xc78, 0xe65a0001}, {0xc78, 0xe55b0001},
+       {0xc78, 0xe45c0001}, {0xc78, 0xe35d0001},
+       {0xc78, 0xe25e0001}, {0xc78, 0xe15f0001},
+       {0xc78, 0x8a600001}, {0xc78, 0x89610001},
+       {0xc78, 0x88620001}, {0xc78, 0x87630001},
+       {0xc78, 0x86640001}, {0xc78, 0x85650001},
+       {0xc78, 0x84660001}, {0xc78, 0x83670001},
+       {0xc78, 0x82680001}, {0xc78, 0x6b690001},
+       {0xc78, 0x6a6a0001}, {0xc78, 0x696b0001},
+       {0xc78, 0x686c0001}, {0xc78, 0x676d0001},
+       {0xc78, 0x666e0001}, {0xc78, 0x656f0001},
+       {0xc78, 0x64700001}, {0xc78, 0x63710001},
+       {0xc78, 0x62720001}, {0xc78, 0x61730001},
+       {0xc78, 0x49740001}, {0xc78, 0x48750001},
+       {0xc78, 0x47760001}, {0xc78, 0x46770001},
+       {0xc78, 0x45780001}, {0xc78, 0x44790001},
+       {0xc78, 0x437a0001}, {0xc78, 0x427b0001},
+       {0xc78, 0x417c0001}, {0xc78, 0x407d0001},
+       {0xc78, 0x407e0001}, {0xc78, 0x407f0001},
+       {0xc50, 0x00040022}, {0xc50, 0x00040020},
+       {0xffff, 0xffffffff}
+};
+
+static struct rtl8xxxu_reg32val rtl8xxx_agc_8192eu_highpa_table[] = {
+       {0xc78, 0xfa000001}, {0xc78, 0xf9010001},
+       {0xc78, 0xf8020001}, {0xc78, 0xf7030001},
+       {0xc78, 0xf6040001}, {0xc78, 0xf5050001},
+       {0xc78, 0xf4060001}, {0xc78, 0xf3070001},
+       {0xc78, 0xf2080001}, {0xc78, 0xf1090001},
+       {0xc78, 0xf00a0001}, {0xc78, 0xef0b0001},
+       {0xc78, 0xee0c0001}, {0xc78, 0xed0d0001},
+       {0xc78, 0xec0e0001}, {0xc78, 0xeb0f0001},
+       {0xc78, 0xea100001}, {0xc78, 0xe9110001},
+       {0xc78, 0xe8120001}, {0xc78, 0xe7130001},
+       {0xc78, 0xe6140001}, {0xc78, 0xe5150001},
+       {0xc78, 0xe4160001}, {0xc78, 0xe3170001},
+       {0xc78, 0xe2180001}, {0xc78, 0xe1190001},
+       {0xc78, 0x8a1a0001}, {0xc78, 0x891b0001},
+       {0xc78, 0x881c0001}, {0xc78, 0x871d0001},
+       {0xc78, 0x861e0001}, {0xc78, 0x851f0001},
+       {0xc78, 0x84200001}, {0xc78, 0x83210001},
+       {0xc78, 0x82220001}, {0xc78, 0x6a230001},
+       {0xc78, 0x69240001}, {0xc78, 0x68250001},
+       {0xc78, 0x67260001}, {0xc78, 0x66270001},
+       {0xc78, 0x65280001}, {0xc78, 0x64290001},
+       {0xc78, 0x632a0001}, {0xc78, 0x622b0001},
+       {0xc78, 0x612c0001}, {0xc78, 0x602d0001},
+       {0xc78, 0x472e0001}, {0xc78, 0x462f0001},
+       {0xc78, 0x45300001}, {0xc78, 0x44310001},
+       {0xc78, 0x43320001}, {0xc78, 0x42330001},
+       {0xc78, 0x41340001}, {0xc78, 0x40350001},
+       {0xc78, 0x40360001}, {0xc78, 0x40370001},
+       {0xc78, 0x40380001}, {0xc78, 0x40390001},
+       {0xc78, 0x403a0001}, {0xc78, 0x403b0001},
+       {0xc78, 0x403c0001}, {0xc78, 0x403d0001},
+       {0xc78, 0x403e0001}, {0xc78, 0x403f0001},
+       {0xc78, 0xfa400001}, {0xc78, 0xf9410001},
+       {0xc78, 0xf8420001}, {0xc78, 0xf7430001},
+       {0xc78, 0xf6440001}, {0xc78, 0xf5450001},
+       {0xc78, 0xf4460001}, {0xc78, 0xf3470001},
+       {0xc78, 0xf2480001}, {0xc78, 0xf1490001},
+       {0xc78, 0xf04a0001}, {0xc78, 0xef4b0001},
+       {0xc78, 0xee4c0001}, {0xc78, 0xed4d0001},
+       {0xc78, 0xec4e0001}, {0xc78, 0xeb4f0001},
+       {0xc78, 0xea500001}, {0xc78, 0xe9510001},
+       {0xc78, 0xe8520001}, {0xc78, 0xe7530001},
+       {0xc78, 0xe6540001}, {0xc78, 0xe5550001},
+       {0xc78, 0xe4560001}, {0xc78, 0xe3570001},
+       {0xc78, 0xe2580001}, {0xc78, 0xe1590001},
+       {0xc78, 0x8a5a0001}, {0xc78, 0x895b0001},
+       {0xc78, 0x885c0001}, {0xc78, 0x875d0001},
+       {0xc78, 0x865e0001}, {0xc78, 0x855f0001},
+       {0xc78, 0x84600001}, {0xc78, 0x83610001},
+       {0xc78, 0x82620001}, {0xc78, 0x6a630001},
+       {0xc78, 0x69640001}, {0xc78, 0x68650001},
+       {0xc78, 0x67660001}, {0xc78, 0x66670001},
+       {0xc78, 0x65680001}, {0xc78, 0x64690001},
+       {0xc78, 0x636a0001}, {0xc78, 0x626b0001},
+       {0xc78, 0x616c0001}, {0xc78, 0x606d0001},
+       {0xc78, 0x476e0001}, {0xc78, 0x466f0001},
+       {0xc78, 0x45700001}, {0xc78, 0x44710001},
+       {0xc78, 0x43720001}, {0xc78, 0x42730001},
+       {0xc78, 0x41740001}, {0xc78, 0x40750001},
+       {0xc78, 0x40760001}, {0xc78, 0x40770001},
+       {0xc78, 0x40780001}, {0xc78, 0x40790001},
+       {0xc78, 0x407a0001}, {0xc78, 0x407b0001},
+       {0xc78, 0x407c0001}, {0xc78, 0x407d0001},
+       {0xc78, 0x407e0001}, {0xc78, 0x407f0001},
+       {0xc50, 0x00040222}, {0xc50, 0x00040220},
+       {0xffff, 0xffffffff}
+};
+
 static struct rtl8xxxu_rfregval rtl8723au_radioa_1t_init_table[] = {
        {0x00, 0x00030159}, {0x01, 0x00031284},
        {0x02, 0x00098000}, {0x03, 0x00039c63},
@@ -963,6 +1331,7 @@ static struct rtl8xxxu_rfregval rtl8723bu_radioa_1t_init_table[] = {
        {0xff, 0xffffffff}
 };
 
+#ifdef CONFIG_RTL8XXXU_UNTESTED
 static struct rtl8xxxu_rfregval rtl8192cu_radioa_2t_init_table[] = {
        {0x00, 0x00030159}, {0x01, 0x00031284},
        {0x02, 0x00098000}, {0x03, 0x00018c63},
@@ -1211,6 +1580,153 @@ static struct rtl8xxxu_rfregval rtl8188ru_radioa_1t_highpa_table[] = {
        {0x00, 0x00030159},
        {0xff, 0xffffffff}
 };
+#endif
+
+static struct rtl8xxxu_rfregval rtl8192eu_radioa_init_table[] = {
+       {0x7f, 0x00000082}, {0x81, 0x0003fc00},
+       {0x00, 0x00030000}, {0x08, 0x00008400},
+       {0x18, 0x00000407}, {0x19, 0x00000012},
+       {0x1b, 0x00000064}, {0x1e, 0x00080009},
+       {0x1f, 0x00000880}, {0x2f, 0x0001a060},
+       {0x3f, 0x00000000}, {0x42, 0x000060c0},
+       {0x57, 0x000d0000}, {0x58, 0x000be180},
+       {0x67, 0x00001552}, {0x83, 0x00000000},
+       {0xb0, 0x000ff9f1}, {0xb1, 0x00055418},
+       {0xb2, 0x0008cc00}, {0xb4, 0x00043083},
+       {0xb5, 0x00008166}, {0xb6, 0x0000803e},
+       {0xb7, 0x0001c69f}, {0xb8, 0x0000407f},
+       {0xb9, 0x00080001}, {0xba, 0x00040001},
+       {0xbb, 0x00000400}, {0xbf, 0x000c0000},
+       {0xc2, 0x00002400}, {0xc3, 0x00000009},
+       {0xc4, 0x00040c91}, {0xc5, 0x00099999},
+       {0xc6, 0x000000a3}, {0xc7, 0x00088820},
+       {0xc8, 0x00076c06}, {0xc9, 0x00000000},
+       {0xca, 0x00080000}, {0xdf, 0x00000180},
+       {0xef, 0x000001a0}, {0x51, 0x00069545},
+       {0x52, 0x0007e45e}, {0x53, 0x00000071},
+       {0x56, 0x00051ff3}, {0x35, 0x000000a8},
+       {0x35, 0x000001e2}, {0x35, 0x000002a8},
+       {0x36, 0x00001c24}, {0x36, 0x00009c24},
+       {0x36, 0x00011c24}, {0x36, 0x00019c24},
+       {0x18, 0x00000c07}, {0x5a, 0x00048000},
+       {0x19, 0x000739d0},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0x34, 0x0000a093}, {0x34, 0x0000908f},
+       {0x34, 0x0000808c}, {0x34, 0x0000704d},
+       {0x34, 0x0000604a}, {0x34, 0x00005047},
+       {0x34, 0x0000400a}, {0x34, 0x00003007},
+       {0x34, 0x00002004}, {0x34, 0x00001001},
+       {0x34, 0x00000000},
+#else
+       /* Regular */
+       {0x34, 0x0000add7}, {0x34, 0x00009dd4},
+       {0x34, 0x00008dd1}, {0x34, 0x00007dce},
+       {0x34, 0x00006dcb}, {0x34, 0x00005dc8},
+       {0x34, 0x00004dc5}, {0x34, 0x000034cc},
+       {0x34, 0x0000244f}, {0x34, 0x0000144c},
+       {0x34, 0x00000014},
+#endif
+       {0x00, 0x00030159},
+       {0x84, 0x00068180},
+       {0x86, 0x0000014e},
+       {0x87, 0x00048e00},
+       {0x8e, 0x00065540},
+       {0x8f, 0x00088000},
+       {0xef, 0x000020a0},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0x3b, 0x000f07b0},
+#else
+       {0x3b, 0x000f02b0},
+#endif
+       {0x3b, 0x000ef7b0}, {0x3b, 0x000d4fb0},
+       {0x3b, 0x000cf060}, {0x3b, 0x000b0090},
+       {0x3b, 0x000a0080}, {0x3b, 0x00090080},
+       {0x3b, 0x0008f780},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0x3b, 0x000787b0},
+#else
+       {0x3b, 0x00078730},
+#endif
+       {0x3b, 0x00060fb0}, {0x3b, 0x0005ffa0},
+       {0x3b, 0x00040620}, {0x3b, 0x00037090},
+       {0x3b, 0x00020080}, {0x3b, 0x0001f060},
+       {0x3b, 0x0000ffb0}, {0xef, 0x000000a0},
+       {0xfe, 0x00000000}, {0x18, 0x0000fc07},
+       {0xfe, 0x00000000}, {0xfe, 0x00000000},
+       {0xfe, 0x00000000}, {0xfe, 0x00000000},
+       {0x1e, 0x00000001}, {0x1f, 0x00080000},
+       {0x00, 0x00033e70},
+       {0xff, 0xffffffff}
+};
+
+static struct rtl8xxxu_rfregval rtl8192eu_radiob_init_table[] = {
+       {0x7f, 0x00000082}, {0x81, 0x0003fc00},
+       {0x00, 0x00030000}, {0x08, 0x00008400},
+       {0x18, 0x00000407}, {0x19, 0x00000012},
+       {0x1b, 0x00000064}, {0x1e, 0x00080009},
+       {0x1f, 0x00000880}, {0x2f, 0x0001a060},
+       {0x3f, 0x00000000}, {0x42, 0x000060c0},
+       {0x57, 0x000d0000}, {0x58, 0x000be180},
+       {0x67, 0x00001552}, {0x7f, 0x00000082},
+       {0x81, 0x0003f000}, {0x83, 0x00000000},
+       {0xdf, 0x00000180}, {0xef, 0x000001a0},
+       {0x51, 0x00069545}, {0x52, 0x0007e42e},
+       {0x53, 0x00000071}, {0x56, 0x00051ff3},
+       {0x35, 0x000000a8}, {0x35, 0x000001e0},
+       {0x35, 0x000002a8}, {0x36, 0x00001ca8},
+       {0x36, 0x00009c24}, {0x36, 0x00011c24},
+       {0x36, 0x00019c24}, {0x18, 0x00000c07},
+       {0x5a, 0x00048000}, {0x19, 0x000739d0},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0x34, 0x0000a093}, {0x34, 0x0000908f},
+       {0x34, 0x0000808c}, {0x34, 0x0000704d},
+       {0x34, 0x0000604a}, {0x34, 0x00005047},
+       {0x34, 0x0000400a}, {0x34, 0x00003007},
+       {0x34, 0x00002004}, {0x34, 0x00001001},
+       {0x34, 0x00000000},
+#else
+       {0x34, 0x0000add7}, {0x34, 0x00009dd4},
+       {0x34, 0x00008dd1}, {0x34, 0x00007dce},
+       {0x34, 0x00006dcb}, {0x34, 0x00005dc8},
+       {0x34, 0x00004dc5}, {0x34, 0x000034cc},
+       {0x34, 0x0000244f}, {0x34, 0x0000144c},
+       {0x34, 0x00000014},
+#endif
+       {0x00, 0x00030159}, {0x84, 0x00068180},
+       {0x86, 0x000000ce}, {0x87, 0x00048a00},
+       {0x8e, 0x00065540}, {0x8f, 0x00088000},
+       {0xef, 0x000020a0},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0x3b, 0x000f07b0},
+#else
+       {0x3b, 0x000f02b0},
+#endif
+
+       {0x3b, 0x000ef7b0}, {0x3b, 0x000d4fb0},
+       {0x3b, 0x000cf060}, {0x3b, 0x000b0090},
+       {0x3b, 0x000a0080}, {0x3b, 0x00090080},
+       {0x3b, 0x0008f780},
+#ifdef EXT_PA_8192EU
+       /* External PA or external LNA */
+       {0x3b, 0x000787b0},
+#else
+       {0x3b, 0x00078730},
+#endif
+       {0x3b, 0x00060fb0}, {0x3b, 0x0005ffa0},
+       {0x3b, 0x00040620}, {0x3b, 0x00037090},
+       {0x3b, 0x00020080}, {0x3b, 0x0001f060},
+       {0x3b, 0x0000ffb0}, {0xef, 0x000000a0},
+       {0x00, 0x00010159}, {0xfe, 0x00000000},
+       {0xfe, 0x00000000}, {0xfe, 0x00000000},
+       {0xfe, 0x00000000}, {0x1e, 0x00000001},
+       {0x1f, 0x00080000}, {0x00, 0x00033e70},
+       {0xff, 0xffffffff}
+};
 
 static struct rtl8xxxu_rfregs rtl8xxxu_rfregs[] = {
        {       /* RF_A */
@@ -1231,7 +1747,7 @@ static struct rtl8xxxu_rfregs rtl8xxxu_rfregs[] = {
        },
 };
 
-static const u32 rtl8723au_iqk_phy_iq_bb_reg[RTL8XXXU_BB_REGS] = {
+static const u32 rtl8xxxu_iqk_phy_iq_bb_reg[RTL8XXXU_BB_REGS] = {
        REG_OFDM0_XA_RX_IQ_IMBALANCE,
        REG_OFDM0_XB_RX_IQ_IMBALANCE,
        REG_OFDM0_ENERGY_CCA_THRES,
@@ -1450,7 +1966,7 @@ static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv,
                                enum rtl8xxxu_rfpath path, u8 reg, u32 data)
 {
        int ret, retval;
-       u32 dataaddr;
+       u32 dataaddr, val32;
 
        if (rtl8xxxu_debug & RTL8XXXU_DEBUG_RFREG_WRITE)
                dev_info(&priv->udev->dev, "%s(%02x) = 0x%06x\n",
@@ -1459,6 +1975,12 @@ static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv,
        data &= FPGA0_LSSI_PARM_DATA_MASK;
        dataaddr = (reg << FPGA0_LSSI_PARM_ADDR_SHIFT) | data;
 
+       if (priv->rtl_chip == RTL8192E) {
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE);
+               val32 &= ~0x20000;
+               rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32);
+       }
+
        /* Use XB for path B */
        ret = rtl8xxxu_write32(priv, rtl8xxxu_rfregs[path].lssiparm, dataaddr);
        if (ret != sizeof(dataaddr))
@@ -1468,6 +1990,12 @@ static int rtl8xxxu_write_rfreg(struct rtl8xxxu_priv *priv,
 
        udelay(1);
 
+       if (priv->rtl_chip == RTL8192E) {
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_POWER_SAVE);
+               val32 |= 0x20000;
+               rtl8xxxu_write32(priv, REG_FPGA0_POWER_SAVE, val32);
+       }
+
        return retval;
 }
 
@@ -1552,7 +2080,7 @@ static void rtl8723bu_write_btreg(struct rtl8xxxu_priv *priv, u8 reg, u8 data)
        rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.bt_mp_oper));
 }
 
-static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv)
+static void rtl8xxxu_gen1_enable_rf(struct rtl8xxxu_priv *priv)
 {
        u8 val8;
        u32 val32;
@@ -1596,13 +2124,11 @@ static void rtl8723a_enable_rf(struct rtl8xxxu_priv *priv)
        rtl8xxxu_write8(priv, REG_TXPAUSE, 0x00);
 }
 
-static void rtl8723a_disable_rf(struct rtl8xxxu_priv *priv)
+static void rtl8xxxu_gen1_disable_rf(struct rtl8xxxu_priv *priv)
 {
        u8 sps0;
        u32 val32;
 
-       rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
-
        sps0 = rtl8xxxu_read8(priv, REG_SPS0_CTRL);
 
        /* RF RX code for preamble power saving */
@@ -1676,7 +2202,10 @@ static int rtl8723a_channel_to_group(int channel)
        return group;
 }
 
-static int rtl8723b_channel_to_group(int channel)
+/*
+ * Valid for rtl8723bu and rtl8192eu
+ */
+static int rtl8xxxu_gen2_channel_to_group(int channel)
 {
        int group;
 
@@ -1694,7 +2223,7 @@ static int rtl8723b_channel_to_group(int channel)
        return group;
 }
 
-static void rtl8723au_config_channel(struct ieee80211_hw *hw)
+static void rtl8xxxu_gen1_config_channel(struct ieee80211_hw *hw)
 {
        struct rtl8xxxu_priv *priv = hw->priv;
        u32 val32, rsr;
@@ -1816,7 +2345,7 @@ static void rtl8723au_config_channel(struct ieee80211_hw *hw)
        }
 }
 
-static void rtl8723bu_config_channel(struct ieee80211_hw *hw)
+static void rtl8xxxu_gen2_config_channel(struct ieee80211_hw *hw)
 {
        struct rtl8xxxu_priv *priv = hw->priv;
        u32 val32, rsr;
@@ -1947,8 +2476,9 @@ static void rtl8723bu_config_channel(struct ieee80211_hw *hw)
 }
 
 static void
-rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
+rtl8xxxu_gen1_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
 {
+       struct rtl8xxxu_power_base *power_base = priv->power_base;
        u8 cck[RTL8723A_MAX_RF_PATHS], ofdm[RTL8723A_MAX_RF_PATHS];
        u8 ofdmbase[RTL8723A_MAX_RF_PATHS], mcsbase[RTL8723A_MAX_RF_PATHS];
        u32 val32, ofdm_a, ofdm_b, mcs_a, mcs_b;
@@ -1957,11 +2487,22 @@ rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
 
        group = rtl8723a_channel_to_group(channel);
 
-       cck[0] = priv->cck_tx_power_index_A[group];
-       cck[1] = priv->cck_tx_power_index_B[group];
+       cck[0] = priv->cck_tx_power_index_A[group] - 1;
+       cck[1] = priv->cck_tx_power_index_B[group] - 1;
+
+       if (priv->hi_pa) {
+               if (cck[0] > 0x20)
+                       cck[0] = 0x20;
+               if (cck[1] > 0x20)
+                       cck[1] = 0x20;
+       }
 
        ofdm[0] = priv->ht40_1s_tx_power_index_A[group];
        ofdm[1] = priv->ht40_1s_tx_power_index_B[group];
+       if (ofdm[0])
+               ofdm[0] -= 1;
+       if (ofdm[1])
+               ofdm[1] -= 1;
 
        ofdmbase[0] = ofdm[0] + priv->ofdm_tx_power_index_diff[group].a;
        ofdmbase[1] = ofdm[1] + priv->ofdm_tx_power_index_diff[group].b;
@@ -2017,27 +2558,39 @@ rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
                ofdmbase[0] << 16 | ofdmbase[0] << 24;
        ofdm_b = ofdmbase[1] | ofdmbase[1] << 8 |
                ofdmbase[1] << 16 | ofdmbase[1] << 24;
-       rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06, ofdm_a);
-       rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE18_06, ofdm_b);
 
-       rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24, ofdm_a);
-       rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE54_24, ofdm_b);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06,
+                        ofdm_a + power_base->reg_0e00);
+       rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE18_06,
+                        ofdm_b + power_base->reg_0830);
+
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24,
+                        ofdm_a + power_base->reg_0e04);
+       rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE54_24,
+                        ofdm_b + power_base->reg_0834);
 
        mcs_a = mcsbase[0] | mcsbase[0] << 8 |
                mcsbase[0] << 16 | mcsbase[0] << 24;
        mcs_b = mcsbase[1] | mcsbase[1] << 8 |
                mcsbase[1] << 16 | mcsbase[1] << 24;
 
-       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS03_MCS00, mcs_a);
-       rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS03_MCS00, mcs_b);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS03_MCS00,
+                        mcs_a + power_base->reg_0e10);
+       rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS03_MCS00,
+                        mcs_b + power_base->reg_083c);
 
-       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04, mcs_a);
-       rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS07_MCS04, mcs_b);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04,
+                        mcs_a + power_base->reg_0e14);
+       rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS07_MCS04,
+                        mcs_b + power_base->reg_0848);
 
-       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS11_MCS08, mcs_a);
-       rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS11_MCS08, mcs_b);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS11_MCS08,
+                        mcs_a + power_base->reg_0e18);
+       rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS11_MCS08,
+                        mcs_b + power_base->reg_084c);
 
-       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS15_MCS12, mcs_a);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS15_MCS12,
+                        mcs_a + power_base->reg_0e1c);
        for (i = 0; i < 3; i++) {
                if (i != 2)
                        val8 = (mcsbase[0] > 8) ? (mcsbase[0] - 8) : 0;
@@ -2045,7 +2598,8 @@ rtl8723a_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
                        val8 = (mcsbase[0] > 6) ? (mcsbase[0] - 6) : 0;
                rtl8xxxu_write8(priv, REG_OFDM0_XC_TX_IQ_IMBALANCE + i, val8);
        }
-       rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS15_MCS12, mcs_b);
+       rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS15_MCS12,
+                        mcs_b + power_base->reg_0868);
        for (i = 0; i < 3; i++) {
                if (i != 2)
                        val8 = (mcsbase[1] > 8) ? (mcsbase[1] - 8) : 0;
@@ -2063,7 +2617,7 @@ rtl8723b_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
        int group, tx_idx;
 
        tx_idx = 0;
-       group = rtl8723b_channel_to_group(channel);
+       group = rtl8xxxu_gen2_channel_to_group(channel);
 
        cck = priv->cck_tx_power_index_B[group];
        val32 = rtl8xxxu_read32(priv, REG_TX_AGC_A_CCK1_MCS32);
@@ -2094,6 +2648,82 @@ rtl8723b_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
        rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04, mcs);
 }
 
+static void
+rtl8192e_set_tx_power(struct rtl8xxxu_priv *priv, int channel, bool ht40)
+{
+       u32 val32, ofdm, mcs;
+       u8 cck, ofdmbase, mcsbase;
+       int group, tx_idx;
+
+       tx_idx = 0;
+       group = rtl8xxxu_gen2_channel_to_group(channel);
+
+       cck = priv->cck_tx_power_index_A[group];
+
+       val32 = rtl8xxxu_read32(priv, REG_TX_AGC_A_CCK1_MCS32);
+       val32 &= 0xffff00ff;
+       val32 |= (cck << 8);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_CCK1_MCS32, val32);
+
+       val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
+       val32 &= 0xff;
+       val32 |= ((cck << 8) | (cck << 16) | (cck << 24));
+       rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
+
+       ofdmbase = priv->ht40_1s_tx_power_index_A[group];
+       ofdmbase += priv->ofdm_tx_power_diff[tx_idx].a;
+       ofdm = ofdmbase | ofdmbase << 8 | ofdmbase << 16 | ofdmbase << 24;
+
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE18_06, ofdm);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_RATE54_24, ofdm);
+
+       mcsbase = priv->ht40_1s_tx_power_index_A[group];
+       if (ht40)
+               mcsbase += priv->ht40_tx_power_diff[tx_idx++].a;
+       else
+               mcsbase += priv->ht20_tx_power_diff[tx_idx++].a;
+       mcs = mcsbase | mcsbase << 8 | mcsbase << 16 | mcsbase << 24;
+
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS03_MCS00, mcs);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS07_MCS04, mcs);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS11_MCS08, mcs);
+       rtl8xxxu_write32(priv, REG_TX_AGC_A_MCS15_MCS12, mcs);
+
+       if (priv->tx_paths > 1) {
+               cck = priv->cck_tx_power_index_B[group];
+
+               val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK1_55_MCS32);
+               val32 &= 0xff;
+               val32 |= ((cck << 8) | (cck << 16) | (cck << 24));
+               rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK1_55_MCS32, val32);
+
+               val32 = rtl8xxxu_read32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11);
+               val32 &= 0xffffff00;
+               val32 |= cck;
+               rtl8xxxu_write32(priv, REG_TX_AGC_B_CCK11_A_CCK2_11, val32);
+
+               ofdmbase = priv->ht40_1s_tx_power_index_B[group];
+               ofdmbase += priv->ofdm_tx_power_diff[tx_idx].b;
+               ofdm = ofdmbase | ofdmbase << 8 |
+                       ofdmbase << 16 | ofdmbase << 24;
+
+               rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE18_06, ofdm);
+               rtl8xxxu_write32(priv, REG_TX_AGC_B_RATE54_24, ofdm);
+
+               mcsbase = priv->ht40_1s_tx_power_index_B[group];
+               if (ht40)
+                       mcsbase += priv->ht40_tx_power_diff[tx_idx++].b;
+               else
+                       mcsbase += priv->ht20_tx_power_diff[tx_idx++].b;
+               mcs = mcsbase | mcsbase << 8 | mcsbase << 16 | mcsbase << 24;
+
+               rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS03_MCS00, mcs);
+               rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS07_MCS04, mcs);
+               rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS11_MCS08, mcs);
+               rtl8xxxu_write32(priv, REG_TX_AGC_B_MCS15_MCS12, mcs);
+       }
+}
+
 static void rtl8xxxu_set_linktype(struct rtl8xxxu_priv *priv,
                                  enum nl80211_iftype linktype)
 {
@@ -2221,7 +2851,8 @@ static int rtl8xxxu_identify_chip(struct rtl8xxxu_priv *priv)
        } else if (val32 & SYS_CFG_TYPE_ID) {
                bonding = rtl8xxxu_read32(priv, REG_HPON_FSM);
                bonding &= HPON_FSM_BONDING_MASK;
-               if (priv->fops->has_s0s1) {
+               if (priv->fops->tx_desc_size ==
+                   sizeof(struct rtl8xxxu_txdesc40)) {
                        if (bonding == HPON_FSM_BONDING_1T2R) {
                                sprintf(priv->chip_name, "8191EU");
                                priv->rf_paths = 2;
@@ -2375,6 +3006,9 @@ static int rtl8723au_parse_efuse(struct rtl8xxxu_priv *priv)
                priv->has_xtalk = 1;
                priv->xtalk = priv->efuse_wifi.efuse8723.xtal_k & 0x3f;
        }
+
+       priv->power_base = &rtl8723a_power_base;
+
        dev_info(&priv->udev->dev, "Vendor: %.7s\n",
                 efuse->vendor_name);
        dev_info(&priv->udev->dev, "Product: %.41s\n",
@@ -2507,9 +3141,14 @@ static int rtl8192cu_parse_efuse(struct rtl8xxxu_priv *priv)
        dev_info(&priv->udev->dev, "Product: %.20s\n",
                 efuse->device_name);
 
+       priv->power_base = &rtl8192c_power_base;
+
        if (efuse->rf_regulatory & 0x20) {
                sprintf(priv->chip_name, "8188RU");
+               priv->rtl_chip = RTL8188R;
                priv->hi_pa = 1;
+               priv->no_pape = 1;
+               priv->power_base = &rtl8188r_power_base;
        }
 
        if (rtl8xxxu_debug & RTL8XXXU_DEBUG_EFUSE) {
@@ -2541,6 +3180,43 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv)
 
        ether_addr_copy(priv->mac_addr, efuse->mac_addr);
 
+       memcpy(priv->cck_tx_power_index_A, efuse->tx_power_index_A.cck_base,
+              sizeof(efuse->tx_power_index_A.cck_base));
+       memcpy(priv->cck_tx_power_index_B, efuse->tx_power_index_B.cck_base,
+              sizeof(efuse->tx_power_index_B.cck_base));
+
+       memcpy(priv->ht40_1s_tx_power_index_A,
+              efuse->tx_power_index_A.ht40_base,
+              sizeof(efuse->tx_power_index_A.ht40_base));
+       memcpy(priv->ht40_1s_tx_power_index_B,
+              efuse->tx_power_index_B.ht40_base,
+              sizeof(efuse->tx_power_index_B.ht40_base));
+
+       priv->ht20_tx_power_diff[0].a =
+               efuse->tx_power_index_A.ht20_ofdm_1s_diff.b;
+       priv->ht20_tx_power_diff[0].b =
+               efuse->tx_power_index_B.ht20_ofdm_1s_diff.b;
+
+       priv->ht40_tx_power_diff[0].a = 0;
+       priv->ht40_tx_power_diff[0].b = 0;
+
+       for (i = 1; i < RTL8723B_TX_COUNT; i++) {
+               priv->ofdm_tx_power_diff[i].a =
+                       efuse->tx_power_index_A.pwr_diff[i - 1].ofdm;
+               priv->ofdm_tx_power_diff[i].b =
+                       efuse->tx_power_index_B.pwr_diff[i - 1].ofdm;
+
+               priv->ht20_tx_power_diff[i].a =
+                       efuse->tx_power_index_A.pwr_diff[i - 1].ht20;
+               priv->ht20_tx_power_diff[i].b =
+                       efuse->tx_power_index_B.pwr_diff[i - 1].ht20;
+
+               priv->ht40_tx_power_diff[i].a =
+                       efuse->tx_power_index_A.pwr_diff[i - 1].ht40;
+               priv->ht40_tx_power_diff[i].b =
+                       efuse->tx_power_index_B.pwr_diff[i - 1].ht40;
+       }
+
        priv->has_xtalk = 1;
        priv->xtalk = priv->efuse_wifi.efuse8192eu.xtal_k & 0x3f;
 
@@ -2562,10 +3238,6 @@ static int rtl8192eu_parse_efuse(struct rtl8xxxu_priv *priv)
                                 raw[i + 6], raw[i + 7]);
                }
        }
-       /*
-        * Temporarily disable 8192eu support
-        */
-       return -EINVAL;
        return 0;
 }
 
@@ -3052,9 +3724,9 @@ static void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv)
 {
        u32 val32;
 
-       val32 = rtl8xxxu_read32(priv, 0x64);
+       val32 = rtl8xxxu_read32(priv, REG_PAD_CTRL1);
        val32 &= ~(BIT(20) | BIT(24));
-       rtl8xxxu_write32(priv, 0x64, val32);
+       rtl8xxxu_write32(priv, REG_PAD_CTRL1, val32);
 
        val32 = rtl8xxxu_read32(priv, REG_GPIO_MUXCFG);
        val32 &= ~BIT(4);
@@ -3087,8 +3759,9 @@ static void rtl8723bu_phy_init_antenna_selection(struct rtl8xxxu_priv *priv)
 }
 
 static int
-rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv, struct rtl8xxxu_reg8val *array)
+rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv)
 {
+       struct rtl8xxxu_reg8val *array = priv->fops->mactable;
        int i, ret;
        u16 reg;
        u8 val;
@@ -3103,12 +3776,13 @@ rtl8xxxu_init_mac(struct rtl8xxxu_priv *priv, struct rtl8xxxu_reg8val *array)
                ret = rtl8xxxu_write8(priv, reg, val);
                if (ret != 1) {
                        dev_warn(&priv->udev->dev,
-                                "Failed to initialize MAC\n");
+                                "Failed to initialize MAC "
+                                "(reg: %04x, val %02x)\n", reg, val);
                        return -EAGAIN;
                }
        }
 
-       if (priv->rtl_chip != RTL8723B)
+       if (priv->rtl_chip != RTL8723B && priv->rtl_chip != RTL8192E)
                rtl8xxxu_write8(priv, REG_MAX_AGGR_NUM, 0x0a);
 
        return 0;
@@ -3140,50 +3814,30 @@ static int rtl8xxxu_init_phy_regs(struct rtl8xxxu_priv *priv,
        return 0;
 }
 
-/*
- * Most of this is black magic retrieved from the old rtl8723au driver
- */
-static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv)
+static void rtl8xxxu_gen1_init_phy_bb(struct rtl8xxxu_priv *priv)
 {
        u8 val8, ldoa15, ldov12d, lpldo, ldohci12;
        u16 val16;
        u32 val32;
 
-       /*
-        * Todo: The vendor driver maintains a table of PHY register
-        *       addresses, which is initialized here. Do we need this?
-        */
-
-       if (priv->rtl_chip == RTL8723B) {
-               val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
-               val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB |
-                       SYS_FUNC_DIO_RF;
-               rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
-
-               rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00);
-       } else {
-               val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL);
-               udelay(2);
-               val8 |= AFE_PLL_320_ENABLE;
-               rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8);
-               udelay(2);
+       val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL);
+       udelay(2);
+       val8 |= AFE_PLL_320_ENABLE;
+       rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8);
+       udelay(2);
 
-               rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff);
-               udelay(2);
+       rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL + 1, 0xff);
+       udelay(2);
 
-               val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
-               val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB;
-               rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
-       }
+       val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+       val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB;
+       rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
 
-       if (priv->rtl_chip != RTL8723B) {
-               /* AFE_XTAL_RF_GATE (bit 14) if addressing as 32 bit register */
-               val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);
-               val32 &= ~AFE_XTAL_RF_GATE;
-               if (priv->has_bluetooth)
-                       val32 &= ~AFE_XTAL_BT_GATE;
-               rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);
-       }
+       val32 = rtl8xxxu_read32(priv, REG_AFE_XTAL_CTRL);
+       val32 &= ~AFE_XTAL_RF_GATE;
+       if (priv->has_bluetooth)
+               val32 &= ~AFE_XTAL_BT_GATE;
+       rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, val32);
 
        /* 6. 0x1f[7:0] = 0x07 */
        val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB;
@@ -3193,43 +3847,110 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv)
                rtl8xxxu_init_phy_regs(priv, rtl8188ru_phy_1t_highpa_table);
        else if (priv->tx_paths == 2)
                rtl8xxxu_init_phy_regs(priv, rtl8192cu_phy_2t_init_table);
-       else if (priv->rtl_chip == RTL8723B) {
-               /*
-                * Why?
-                */
-               rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xe3);
-               rtl8xxxu_write8(priv, REG_AFE_XTAL_CTRL + 1, 0x80);
-               rtl8xxxu_init_phy_regs(priv, rtl8723b_phy_1t_init_table);
-       } else
+       else
                rtl8xxxu_init_phy_regs(priv, rtl8723a_phy_1t_init_table);
 
-
-       if (priv->rtl_chip == RTL8188C && priv->hi_pa &&
+       if (priv->rtl_chip == RTL8188R && priv->hi_pa &&
            priv->vendor_umc && priv->chip_cut == 1)
                rtl8xxxu_write8(priv, REG_OFDM0_AGC_PARM1 + 2, 0x50);
 
-       if (priv->tx_paths == 1 && priv->rx_paths == 2) {
-               /*
-                * For 1T2R boards, patch the registers.
-                *
-                * It looks like 8191/2 1T2R boards use path B for TX
-                */
-               val32 = rtl8xxxu_read32(priv, REG_FPGA0_TX_INFO);
-               val32 &= ~(BIT(0) | BIT(1));
-               val32 |= BIT(1);
-               rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, val32);
+       if (priv->hi_pa)
+               rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_highpa_table);
+       else
+               rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table);
 
-               val32 = rtl8xxxu_read32(priv, REG_FPGA1_TX_INFO);
-               val32 &= ~0x300033;
-               val32 |= 0x200022;
-               rtl8xxxu_write32(priv, REG_FPGA1_TX_INFO, val32);
+       ldoa15 = LDOA15_ENABLE | LDOA15_OBUF;
+       ldov12d = LDOV12D_ENABLE | BIT(2) | (2 << LDOV12D_VADJ_SHIFT);
+       ldohci12 = 0x57;
+       lpldo = 1;
+       val32 = (lpldo << 24) | (ldohci12 << 16) | (ldov12d << 8) | ldoa15;
+       rtl8xxxu_write32(priv, REG_LDOA15_CTRL, val32);
+}
 
-               val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING);
-               val32 &= 0xff000000;
-               val32 |= 0x45000000;
-               rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32);
+static void rtl8723bu_init_phy_bb(struct rtl8xxxu_priv *priv)
+{
+       u8 val8;
+       u16 val16;
 
-               val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
+       val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+       val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB | SYS_FUNC_DIO_RF;
+       rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+
+       rtl8xxxu_write32(priv, REG_S0S1_PATH_SWITCH, 0x00);
+
+       /* 6. 0x1f[7:0] = 0x07 */
+       val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB;
+       rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
+
+       /* Why? */
+       rtl8xxxu_write8(priv, REG_SYS_FUNC, 0xe3);
+       rtl8xxxu_write8(priv, REG_AFE_XTAL_CTRL + 1, 0x80);
+       rtl8xxxu_init_phy_regs(priv, rtl8723b_phy_1t_init_table);
+
+       rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_8723bu_table);
+}
+
+static void rtl8192eu_init_phy_bb(struct rtl8xxxu_priv *priv)
+{
+       u8 val8;
+       u16 val16;
+
+       val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+       val16 |= SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB | SYS_FUNC_DIO_RF;
+       rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+
+       /* 6. 0x1f[7:0] = 0x07 */
+       val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB;
+       rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
+
+       val16 = rtl8xxxu_read16(priv, REG_SYS_FUNC);
+       val16 |= (SYS_FUNC_USBA | SYS_FUNC_USBD | SYS_FUNC_DIO_RF |
+                 SYS_FUNC_BB_GLB_RSTN | SYS_FUNC_BBRSTB);
+       rtl8xxxu_write16(priv, REG_SYS_FUNC, val16);
+       val8 = RF_ENABLE | RF_RSTB | RF_SDMRSTB;
+       rtl8xxxu_write8(priv, REG_RF_CTRL, val8);
+       rtl8xxxu_init_phy_regs(priv, rtl8192eu_phy_init_table);
+
+       if (priv->hi_pa)
+               rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_8192eu_highpa_table);
+       else
+               rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_8192eu_std_table);
+}
+
+/*
+ * Most of this is black magic retrieved from the old rtl8723au driver
+ */
+static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv)
+{
+       u8 val8;
+       u32 val32;
+
+       priv->fops->init_phy_bb(priv);
+
+       if (priv->tx_paths == 1 && priv->rx_paths == 2) {
+               /*
+                * For 1T2R boards, patch the registers.
+                *
+                * It looks like 8191/2 1T2R boards use path B for TX
+                */
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_TX_INFO);
+               val32 &= ~(BIT(0) | BIT(1));
+               val32 |= BIT(1);
+               rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, val32);
+
+               val32 = rtl8xxxu_read32(priv, REG_FPGA1_TX_INFO);
+               val32 &= ~0x300033;
+               val32 |= 0x200022;
+               rtl8xxxu_write32(priv, REG_FPGA1_TX_INFO, val32);
+
+               val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING);
+               val32 &= ~CCK0_AFE_RX_MASK;
+               val32 &= 0x00ffffff;
+               val32 |= 0x40000000;
+               val32 |= CCK0_AFE_RX_ANT_B;
+               rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32);
+
+               val32 = rtl8xxxu_read32(priv, REG_OFDM0_TRX_PATH_ENABLE);
                val32 &= ~(OFDM_RF_PATH_RX_MASK | OFDM_RF_PATH_TX_MASK);
                val32 |= (OFDM_RF_PATH_RX_A | OFDM_RF_PATH_RX_B |
                          OFDM_RF_PATH_TX_B);
@@ -3266,13 +3987,6 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv)
                rtl8xxxu_write32(priv, REG_TX_TO_TX, val32);
        }
 
-       if (priv->rtl_chip == RTL8723B)
-               rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_8723bu_table);
-       else if (priv->hi_pa)
-               rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_highpa_table);
-       else
-               rtl8xxxu_init_phy_regs(priv, rtl8xxx_agc_standard_table);
-
        if (priv->has_xtalk) {
                val32 = rtl8xxxu_read32(priv, REG_MAC_PHY_CTRL);
 
@@ -3283,16 +3997,8 @@ static int rtl8xxxu_init_phy_bb(struct rtl8xxxu_priv *priv)
                rtl8xxxu_write32(priv, REG_MAC_PHY_CTRL, val32);
        }
 
-       if (priv->rtl_chip != RTL8723B && priv->rtl_chip != RTL8192E) {
-               ldoa15 = LDOA15_ENABLE | LDOA15_OBUF;
-               ldov12d = LDOV12D_ENABLE | BIT(2) | (2 << LDOV12D_VADJ_SHIFT);
-               ldohci12 = 0x57;
-               lpldo = 1;
-               val32 = (lpldo << 24) | (ldohci12 << 16) |
-                       (ldov12d << 8) | ldoa15;
-
-               rtl8xxxu_write32(priv, REG_LDOA15_CTRL, val32);
-       }
+       if (priv->rtl_chip == RTL8192E)
+               rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x000f81fb);
 
        return 0;
 }
@@ -3410,6 +4116,77 @@ static int rtl8xxxu_init_phy_rf(struct rtl8xxxu_priv *priv,
        return 0;
 }
 
+static int rtl8723au_init_phy_rf(struct rtl8xxxu_priv *priv)
+{
+       int ret;
+
+       ret = rtl8xxxu_init_phy_rf(priv, rtl8723au_radioa_1t_init_table, RF_A);
+
+       /* Reduce 80M spur */
+       rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d);
+       rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
+       rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82);
+       rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
+
+       return ret;
+}
+
+static int rtl8723bu_init_phy_rf(struct rtl8xxxu_priv *priv)
+{
+       int ret;
+
+       ret = rtl8xxxu_init_phy_rf(priv, rtl8723bu_radioa_1t_init_table, RF_A);
+       /*
+        * PHY LCK
+        */
+       rtl8xxxu_write_rfreg(priv, RF_A, 0xb0, 0xdfbe0);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, 0x8c01);
+       msleep(200);
+       rtl8xxxu_write_rfreg(priv, RF_A, 0xb0, 0xdffe0);
+
+       return ret;
+}
+
+#ifdef CONFIG_RTL8XXXU_UNTESTED
+static int rtl8192cu_init_phy_rf(struct rtl8xxxu_priv *priv)
+{
+       struct rtl8xxxu_rfregval *rftable;
+       int ret;
+
+       if (priv->rtl_chip == RTL8188R) {
+               rftable = rtl8188ru_radioa_1t_highpa_table;
+               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+       } else if (priv->rf_paths == 1) {
+               rftable = rtl8192cu_radioa_1t_init_table;
+               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+       } else {
+               rftable = rtl8192cu_radioa_2t_init_table;
+               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
+               if (ret)
+                       goto exit;
+               rftable = rtl8192cu_radiob_2t_init_table;
+               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_B);
+       }
+
+exit:
+       return ret;
+}
+#endif
+
+static int rtl8192eu_init_phy_rf(struct rtl8xxxu_priv *priv)
+{
+       int ret;
+
+       ret = rtl8xxxu_init_phy_rf(priv, rtl8192eu_radioa_init_table, RF_A);
+       if (ret)
+               goto exit;
+
+       ret = rtl8xxxu_init_phy_rf(priv, rtl8192eu_radiob_init_table, RF_B);
+
+exit:
+       return ret;
+}
+
 static int rtl8xxxu_llt_write(struct rtl8xxxu_priv *priv, u8 address, u8 data)
 {
        int ret = -EBUSY;
@@ -3818,8 +4595,8 @@ static bool rtl8xxxu_simularity_compare(struct rtl8xxxu_priv *priv,
        return false;
 }
 
-static bool rtl8723bu_simularity_compare(struct rtl8xxxu_priv *priv,
-                                        int result[][8], int c1, int c2)
+static bool rtl8xxxu_gen2_simularity_compare(struct rtl8xxxu_priv *priv,
+                                            int result[][8], int c1, int c2)
 {
        u32 i, j, diff, simubitmap, bound = 0;
        int candidate[2] = {-1, -1};    /* for path A and path B */
@@ -4389,138 +5166,425 @@ out:
        return result;
 }
 
-#ifdef RTL8723BU_PATH_B
-static int rtl8723bu_iqk_path_b(struct rtl8xxxu_priv *priv)
+static int rtl8192eu_iqk_path_a(struct rtl8xxxu_priv *priv)
 {
-       u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc, path_sel;
+       u32 reg_eac, reg_e94, reg_e9c;
        int result = 0;
 
-       path_sel = rtl8xxxu_read32(priv, REG_S0S1_PATH_SWITCH);
+       /*
+        * TX IQK
+        * PA/PAD controlled by 0x0
+        */
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00180);
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
 
-       val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
-       val32 &= 0x000000ff;
-       rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
+       /* Path A IQK setting */
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x18008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
 
-       /* One shot, path B LOK & IQK */
-       rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000002);
-       rtl8xxxu_write32(priv, REG_IQK_AGC_CONT, 0x00000000);
+       rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82140303);
+       rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x68160000);
 
-       mdelay(1);
+       /* LO calibration setting */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00462911);
+
+       /* One shot, path A LOK & IQK */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf9000000);
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
+
+       mdelay(10);
 
        /* Check failed */
        reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
-       reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
-       reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
-       reg_ec4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
-       reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
+       reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A);
+       reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A);
 
-       if (!(reg_eac & BIT(31)) &&
-           ((reg_eb4 & 0x03ff0000) != 0x01420000) &&
-           ((reg_ebc & 0x03ff0000) != 0x00420000))
+       if (!(reg_eac & BIT(28)) &&
+           ((reg_e94 & 0x03ff0000) != 0x01420000) &&
+           ((reg_e9c & 0x03ff0000) != 0x00420000))
                result |= 0x01;
-       else
-               goto out;
 
-       if (!(reg_eac & BIT(30)) &&
-           (((reg_ec4 & 0x03ff0000) >> 16) != 0x132) &&
-           (((reg_ecc & 0x03ff0000) >> 16) != 0x36))
-               result |= 0x02;
-       else
-               dev_warn(&priv->udev->dev, "%s: Path B RX IQK failed!\n",
-                        __func__);
-out:
        return result;
 }
-#endif
 
-static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
-                                    int result[][8], int t)
+static int rtl8192eu_rx_iqk_path_a(struct rtl8xxxu_priv *priv)
 {
-       struct device *dev = &priv->udev->dev;
-       u32 i, val32;
-       int path_a_ok, path_b_ok;
-       int retry = 2;
-       const u32 adda_regs[RTL8XXXU_ADDA_REGS] = {
-               REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH,
-               REG_RX_WAIT_CCA, REG_TX_CCK_RFON,
-               REG_TX_CCK_BBON, REG_TX_OFDM_RFON,
-               REG_TX_OFDM_BBON, REG_TX_TO_RX,
-               REG_TX_TO_TX, REG_RX_CCK,
-               REG_RX_OFDM, REG_RX_WAIT_RIFS,
-               REG_RX_TO_RX, REG_STANDBY,
-               REG_SLEEP, REG_PMPD_ANAEN
-       };
-       const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = {
-               REG_TXPAUSE, REG_BEACON_CTRL,
-               REG_BEACON_CTRL_1, REG_GPIO_MUXCFG
-       };
-       const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = {
-               REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR,
-               REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B,
-               REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE,
-               REG_FPGA0_XB_RF_INT_OE, REG_FPGA0_RF_MODE
-       };
-
-       /*
-        * Note: IQ calibration must be performed after loading
-        *       PHY_REG.txt , and radio_a, radio_b.txt
-        */
+       u32 reg_ea4, reg_eac, reg_e94, reg_e9c, val32;
+       int result = 0;
 
-       if (t == 0) {
-               /* Save ADDA parameters, turn Path A ADDA on */
-               rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup,
-                                  RTL8XXXU_ADDA_REGS);
-               rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
-               rtl8xxxu_save_regs(priv, iqk_bb_regs,
-                                  priv->bb_backup, RTL8XXXU_BB_REGS);
-       }
+       /* Leave IQK mode */
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00);
 
-       rtl8xxxu_path_adda_on(priv, adda_regs, true);
+       /* Enable path A PA in TX IQK mode */
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf117b);
 
-       if (t == 0) {
-               val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1);
-               if (val32 & FPGA0_HSSI_PARM1_PI)
-                       priv->pi_enabled = 1;
-       }
+       /* PA/PAD control by 0x56, and set = 0x0 */
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00980);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x51000);
 
-       if (!priv->pi_enabled) {
-               /* Switch BB to PI mode to do IQ Calibration. */
-               rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100);
-               rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100);
-       }
+       /* Enter IQK mode */
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
 
-       val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
-       val32 &= ~FPGA_RF_MODE_CCK;
-       rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+       /* TX IQK setting */
+       rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
+       rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
 
-       rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600);
-       rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4);
-       rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000);
+       /* path-A IQK setting */
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x18008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
 
-       val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL);
-       val32 |= (FPGA0_RF_PAPE | (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT));
-       rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
+       rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c1f);
+       rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x68160c1f);
 
-       val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
-       val32 &= ~BIT(10);
-       rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
-       val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE);
-       val32 &= ~BIT(10);
-       rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32);
+       /* LO calibration setting */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911);
 
-       if (priv->tx_paths > 1) {
-               rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
-               rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM, 0x00010000);
-       }
+       /* One shot, path A LOK & IQK */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa000000);
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
 
-       /* MAC settings */
-       rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup);
+       mdelay(10);
 
-       /* Page B init */
-       rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x00080000);
+       /* Check failed */
+       reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+       reg_e94 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_A);
+       reg_e9c = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_A);
 
-       if (priv->tx_paths > 1)
-               rtl8xxxu_write32(priv, REG_CONFIG_ANT_B, 0x00080000);
+       if (!(reg_eac & BIT(28)) &&
+           ((reg_e94 & 0x03ff0000) != 0x01420000) &&
+           ((reg_e9c & 0x03ff0000) != 0x00420000)) {
+               result |= 0x01;
+       } else {
+               /* PA/PAD controlled by 0x0 */
+               rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+               rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x180);
+               goto out;
+       }
+
+       val32 = 0x80007c00 |
+               (reg_e94 & 0x03ff0000) | ((reg_e9c >> 16) & 0x03ff);
+       rtl8xxxu_write32(priv, REG_TX_IQK, val32);
+
+       /* Modify RX IQK mode table */
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, 0x800a0);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0000f);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7ffa);
+
+       /* PA/PAD control by 0x56, and set = 0x0 */
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x00980);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_56, 0x51000);
+
+       /* Enter IQK mode */
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+
+       /* IQK setting */
+       rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
+
+       /* Path A IQK setting */
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x18008c1c);
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
+
+       rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c1f);
+       rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160c1f);
+
+       /* LO calibration setting */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a891);
+
+       /* One shot, path A LOK & IQK */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa000000);
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
+
+       mdelay(10);
+
+       reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+       reg_ea4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_A_2);
+
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_DF, 0x180);
+
+       if (!(reg_eac & BIT(27)) &&
+           ((reg_ea4 & 0x03ff0000) != 0x01320000) &&
+           ((reg_eac & 0x03ff0000) != 0x00360000))
+               result |= 0x02;
+       else
+               dev_warn(&priv->udev->dev, "%s: Path A RX IQK failed!\n",
+                        __func__);
+
+out:
+       return result;
+}
+
+static int rtl8192eu_iqk_path_b(struct rtl8xxxu_priv *priv)
+{
+       u32 reg_eac, reg_eb4, reg_ebc;
+       int result = 0;
+
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00180);
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+
+       /* Path B IQK setting */
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x18008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
+
+       rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x821403e2);
+       rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x68160000);
+
+       /* LO calibration setting */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x00492911);
+
+       /* One shot, path A LOK & IQK */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa000000);
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
+
+       mdelay(1);
+
+       /* Check failed */
+       reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+       reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+       reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+
+       if (!(reg_eac & BIT(31)) &&
+           ((reg_eb4 & 0x03ff0000) != 0x01420000) &&
+           ((reg_ebc & 0x03ff0000) != 0x00420000))
+               result |= 0x01;
+       else
+               dev_warn(&priv->udev->dev, "%s: Path B IQK failed!\n",
+                        __func__);
+
+       return result;
+}
+
+static int rtl8192eu_rx_iqk_path_b(struct rtl8xxxu_priv *priv)
+{
+       u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc, val32;
+       int result = 0;
+
+       /* Leave IQK mode */
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+
+       /* Enable path A PA in TX IQK mode */
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_WE_LUT, 0x800a0);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x30000);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G1, 0x0000f);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf117b);
+
+       /* PA/PAD control by 0x56, and set = 0x0 */
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00980);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x51000);
+
+       /* Enter IQK mode */
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+
+       /* TX IQK setting */
+       rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
+       rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
+
+       /* path-A IQK setting */
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x18008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x38008c1c);
+
+       rtl8xxxu_write32(priv, REG_TX_IQK_PI_B, 0x82160c1f);
+       rtl8xxxu_write32(priv, REG_RX_IQK_PI_B, 0x68160c1f);
+
+       /* LO calibration setting */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a911);
+
+       /* One shot, path A LOK & IQK */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa000000);
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
+
+       mdelay(10);
+
+       /* Check failed */
+       reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+       reg_eb4 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+       reg_ebc = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+
+       if (!(reg_eac & BIT(31)) &&
+           ((reg_eb4 & 0x03ff0000) != 0x01420000) &&
+           ((reg_ebc & 0x03ff0000) != 0x00420000)) {
+               result |= 0x01;
+       } else {
+               /*
+                * PA/PAD controlled by 0x0
+                * Vendor driver restores RF_A here which I believe is a bug
+                */
+               rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+               rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x180);
+               goto out;
+       }
+
+       val32 = 0x80007c00 |
+               (reg_eb4 & 0x03ff0000) | ((reg_ebc >> 16) & 0x03ff);
+       rtl8xxxu_write32(priv, REG_TX_IQK, val32);
+
+       /* Modify RX IQK mode table */
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_WE_LUT, 0x800a0);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_RCK_OS, 0x30000);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G1, 0x0000f);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_TXPA_G2, 0xf7ffa);
+
+       /* PA/PAD control by 0x56, and set = 0x0 */
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x00980);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_56, 0x51000);
+
+       /* Enter IQK mode */
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+
+       /* IQK setting */
+       rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
+
+       /* Path A IQK setting */
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_TX_IQK_TONE_B, 0x38008c1c);
+       rtl8xxxu_write32(priv, REG_RX_IQK_TONE_B, 0x18008c1c);
+
+       rtl8xxxu_write32(priv, REG_TX_IQK_PI_A, 0x82160c1f);
+       rtl8xxxu_write32(priv, REG_RX_IQK_PI_A, 0x28160c1f);
+
+       /* LO calibration setting */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_RSP, 0x0046a891);
+
+       /* One shot, path A LOK & IQK */
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xfa000000);
+       rtl8xxxu_write32(priv, REG_IQK_AGC_PTS, 0xf8000000);
+
+       mdelay(10);
+
+       reg_eac = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_A_2);
+       reg_ec4 = rtl8xxxu_read32(priv, REG_RX_POWER_BEFORE_IQK_B_2);
+       reg_ecc = rtl8xxxu_read32(priv, REG_RX_POWER_AFTER_IQK_B_2);
+
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
+       rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_UNKNOWN_DF, 0x180);
+
+       if (!(reg_eac & BIT(30)) &&
+           ((reg_ec4 & 0x03ff0000) != 0x01320000) &&
+           ((reg_ecc & 0x03ff0000) != 0x00360000))
+               result |= 0x02;
+       else
+               dev_warn(&priv->udev->dev, "%s: Path B RX IQK failed!\n",
+                        __func__);
+
+out:
+       return result;
+}
+
+static void rtl8xxxu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
+                                    int result[][8], int t)
+{
+       struct device *dev = &priv->udev->dev;
+       u32 i, val32;
+       int path_a_ok, path_b_ok;
+       int retry = 2;
+       const u32 adda_regs[RTL8XXXU_ADDA_REGS] = {
+               REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH,
+               REG_RX_WAIT_CCA, REG_TX_CCK_RFON,
+               REG_TX_CCK_BBON, REG_TX_OFDM_RFON,
+               REG_TX_OFDM_BBON, REG_TX_TO_RX,
+               REG_TX_TO_TX, REG_RX_CCK,
+               REG_RX_OFDM, REG_RX_WAIT_RIFS,
+               REG_RX_TO_RX, REG_STANDBY,
+               REG_SLEEP, REG_PMPD_ANAEN
+       };
+       const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = {
+               REG_TXPAUSE, REG_BEACON_CTRL,
+               REG_BEACON_CTRL_1, REG_GPIO_MUXCFG
+       };
+       const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = {
+               REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR,
+               REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B,
+               REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE,
+               REG_FPGA0_XB_RF_INT_OE, REG_FPGA0_RF_MODE
+       };
+
+       /*
+        * Note: IQ calibration must be performed after loading
+        *       PHY_REG.txt , and radio_a, radio_b.txt
+        */
+
+       if (t == 0) {
+               /* Save ADDA parameters, turn Path A ADDA on */
+               rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup,
+                                  RTL8XXXU_ADDA_REGS);
+               rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
+               rtl8xxxu_save_regs(priv, iqk_bb_regs,
+                                  priv->bb_backup, RTL8XXXU_BB_REGS);
+       }
+
+       rtl8xxxu_path_adda_on(priv, adda_regs, true);
+
+       if (t == 0) {
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_HSSI_PARM1);
+               if (val32 & FPGA0_HSSI_PARM1_PI)
+                       priv->pi_enabled = 1;
+       }
+
+       if (!priv->pi_enabled) {
+               /* Switch BB to PI mode to do IQ Calibration. */
+               rtl8xxxu_write32(priv, REG_FPGA0_XA_HSSI_PARM1, 0x01000100);
+               rtl8xxxu_write32(priv, REG_FPGA0_XB_HSSI_PARM1, 0x01000100);
+       }
+
+       val32 = rtl8xxxu_read32(priv, REG_FPGA0_RF_MODE);
+       val32 &= ~FPGA_RF_MODE_CCK;
+       rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
+
+       rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600);
+       rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4);
+       rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000);
+
+       if (!priv->no_pape) {
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL);
+               val32 |= (FPGA0_RF_PAPE |
+                         (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT));
+               rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
+       }
+
+       val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
+       val32 &= ~BIT(10);
+       rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
+       val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE);
+       val32 &= ~BIT(10);
+       rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32);
+
+       if (priv->tx_paths > 1) {
+               rtl8xxxu_write32(priv, REG_FPGA0_XA_LSSI_PARM, 0x00010000);
+               rtl8xxxu_write32(priv, REG_FPGA0_XB_LSSI_PARM, 0x00010000);
+       }
+
+       /* MAC settings */
+       rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup);
+
+       /* Page B init */
+       rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x00080000);
+
+       if (priv->tx_paths > 1)
+               rtl8xxxu_write32(priv, REG_CONFIG_ANT_B, 0x00080000);
 
        /* IQ calibration setting */
        rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
@@ -4692,55 +5756,232 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
        rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4);
        rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22204000);
 
-#ifdef RTL8723BU_PATH_B
-       /* Set RF mode to standby Path B */
-       if (priv->tx_paths > 1)
-               rtl8xxxu_write_rfreg(priv, RF_B, RF6052_REG_AC, 0x10000);
-#endif
+       /*
+        * RX IQ calibration setting for 8723B D cut large current issue
+        * when leaving IPS
+        */
+       val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
+       val32 &= 0x000000ff;
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
 
-#if 0
-       /* Page B init */
-       rtl8xxxu_write32(priv, REG_CONFIG_ANT_A, 0x0f600000);
+       val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_WE_LUT);
+       val32 |= 0x80000;
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, val32);
 
-       if (priv->tx_paths > 1)
-               rtl8xxxu_write32(priv, REG_CONFIG_ANT_B, 0x0f600000);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0001f);
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7fb7);
+
+       val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_ED);
+       val32 |= 0x20;
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_ED, val32);
+
+       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_43, 0x60fbd);
+
+       for (i = 0; i < retry; i++) {
+               path_a_ok = rtl8723bu_iqk_path_a(priv);
+               if (path_a_ok == 0x01) {
+                       val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
+                       val32 &= 0x000000ff;
+                       rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
+
+                       val32 = rtl8xxxu_read32(priv,
+                                               REG_TX_POWER_BEFORE_IQK_A);
+                       result[t][0] = (val32 >> 16) & 0x3ff;
+                       val32 = rtl8xxxu_read32(priv,
+                                               REG_TX_POWER_AFTER_IQK_A);
+                       result[t][1] = (val32 >> 16) & 0x3ff;
+
+                       break;
+               }
+       }
+
+       if (!path_a_ok)
+               dev_dbg(dev, "%s: Path A TX IQK failed!\n", __func__);
+
+       for (i = 0; i < retry; i++) {
+               path_a_ok = rtl8723bu_rx_iqk_path_a(priv);
+               if (path_a_ok == 0x03) {
+                       val32 = rtl8xxxu_read32(priv,
+                                               REG_RX_POWER_BEFORE_IQK_A_2);
+                       result[t][2] = (val32 >> 16) & 0x3ff;
+                       val32 = rtl8xxxu_read32(priv,
+                                               REG_RX_POWER_AFTER_IQK_A_2);
+                       result[t][3] = (val32 >> 16) & 0x3ff;
+
+                       break;
+               }
+       }
+
+       if (!path_a_ok)
+               dev_dbg(dev, "%s: Path A RX IQK failed!\n", __func__);
+
+       if (priv->tx_paths > 1) {
+#if 1
+               dev_warn(dev, "%s: Path B not supported\n", __func__);
+#else
+
+               /*
+                * Path A into standby
+                */
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
+               val32 &= 0x000000ff;
+               rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
+               rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0x10000);
+
+               val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
+               val32 &= 0x000000ff;
+               val32 |= 0x80800000;
+               rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
+
+               /* Turn Path B ADDA on */
+               rtl8xxxu_path_adda_on(priv, adda_regs, false);
+
+               for (i = 0; i < retry; i++) {
+                       path_b_ok = rtl8xxxu_iqk_path_b(priv);
+                       if (path_b_ok == 0x03) {
+                               val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
+                               result[t][4] = (val32 >> 16) & 0x3ff;
+                               val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
+                               result[t][5] = (val32 >> 16) & 0x3ff;
+                               break;
+                       }
+               }
+
+               if (!path_b_ok)
+                       dev_dbg(dev, "%s: Path B IQK failed!\n", __func__);
+
+               for (i = 0; i < retry; i++) {
+                       path_b_ok = rtl8723bu_rx_iqk_path_b(priv);
+                       if (path_a_ok == 0x03) {
+                               val32 = rtl8xxxu_read32(priv,
+                                                       REG_RX_POWER_BEFORE_IQK_B_2);
+                               result[t][6] = (val32 >> 16) & 0x3ff;
+                               val32 = rtl8xxxu_read32(priv,
+                                                       REG_RX_POWER_AFTER_IQK_B_2);
+                               result[t][7] = (val32 >> 16) & 0x3ff;
+                               break;
+                       }
+               }
+
+               if (!path_b_ok)
+                       dev_dbg(dev, "%s: Path B RX IQK failed!\n", __func__);
 #endif
+       }
+
+       /* Back to BB mode, load original value */
+       val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
+       val32 &= 0x000000ff;
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
+
+       if (t) {
+               /* Reload ADDA power saving parameters */
+               rtl8xxxu_restore_regs(priv, adda_regs, priv->adda_backup,
+                                     RTL8XXXU_ADDA_REGS);
+
+               /* Reload MAC parameters */
+               rtl8xxxu_restore_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
+
+               /* Reload BB parameters */
+               rtl8xxxu_restore_regs(priv, iqk_bb_regs,
+                                     priv->bb_backup, RTL8XXXU_BB_REGS);
+
+               /* Restore RX initial gain */
+               val32 = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1);
+               val32 &= 0xffffff00;
+               rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, val32 | 0x50);
+               rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, val32 | xa_agc);
+
+               if (priv->tx_paths > 1) {
+                       val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_AGC_CORE1);
+                       val32 &= 0xffffff00;
+                       rtl8xxxu_write32(priv, REG_OFDM0_XB_AGC_CORE1,
+                                        val32 | 0x50);
+                       rtl8xxxu_write32(priv, REG_OFDM0_XB_AGC_CORE1,
+                                        val32 | xb_agc);
+               }
+
+               /* Load 0xe30 IQC default value */
+               rtl8xxxu_write32(priv, REG_TX_IQK_TONE_A, 0x01008c00);
+               rtl8xxxu_write32(priv, REG_RX_IQK_TONE_A, 0x01008c00);
+       }
+}
+
+static void rtl8192eu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
+                                     int result[][8], int t)
+{
+       struct device *dev = &priv->udev->dev;
+       u32 i, val32;
+       int path_a_ok, path_b_ok;
+       int retry = 2;
+       const u32 adda_regs[RTL8XXXU_ADDA_REGS] = {
+               REG_FPGA0_XCD_SWITCH_CTRL, REG_BLUETOOTH,
+               REG_RX_WAIT_CCA, REG_TX_CCK_RFON,
+               REG_TX_CCK_BBON, REG_TX_OFDM_RFON,
+               REG_TX_OFDM_BBON, REG_TX_TO_RX,
+               REG_TX_TO_TX, REG_RX_CCK,
+               REG_RX_OFDM, REG_RX_WAIT_RIFS,
+               REG_RX_TO_RX, REG_STANDBY,
+               REG_SLEEP, REG_PMPD_ANAEN
+       };
+       const u32 iqk_mac_regs[RTL8XXXU_MAC_REGS] = {
+               REG_TXPAUSE, REG_BEACON_CTRL,
+               REG_BEACON_CTRL_1, REG_GPIO_MUXCFG
+       };
+       const u32 iqk_bb_regs[RTL8XXXU_BB_REGS] = {
+               REG_OFDM0_TRX_PATH_ENABLE, REG_OFDM0_TR_MUX_PAR,
+               REG_FPGA0_XCD_RF_SW_CTRL, REG_CONFIG_ANT_A, REG_CONFIG_ANT_B,
+               REG_FPGA0_XAB_RF_SW_CTRL, REG_FPGA0_XA_RF_INT_OE,
+               REG_FPGA0_XB_RF_INT_OE, REG_CCK0_AFE_SETTING
+       };
+       u8 xa_agc = rtl8xxxu_read32(priv, REG_OFDM0_XA_AGC_CORE1) & 0xff;
+       u8 xb_agc = rtl8xxxu_read32(priv, REG_OFDM0_XB_AGC_CORE1) & 0xff;
+
+       /*
+        * Note: IQ calibration must be performed after loading
+        *       PHY_REG.txt , and radio_a, radio_b.txt
+        */
+
+       if (t == 0) {
+               /* Save ADDA parameters, turn Path A ADDA on */
+               rtl8xxxu_save_regs(priv, adda_regs, priv->adda_backup,
+                                  RTL8XXXU_ADDA_REGS);
+               rtl8xxxu_save_mac_regs(priv, iqk_mac_regs, priv->mac_backup);
+               rtl8xxxu_save_regs(priv, iqk_bb_regs,
+                                  priv->bb_backup, RTL8XXXU_BB_REGS);
+       }
+
+       rtl8xxxu_path_adda_on(priv, adda_regs, true);
 
-       /*
-        * RX IQ calibration setting for 8723B D cut large current issue
-        * when leaving IPS
-        */
-       val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
-       val32 &= 0x000000ff;
-       rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
+       /* MAC settings */
+       rtl8xxxu_mac_calibration(priv, iqk_mac_regs, priv->mac_backup);
 
-       val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_WE_LUT);
-       val32 |= 0x80000;
-       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_WE_LUT, val32);
+       val32 = rtl8xxxu_read32(priv, REG_CCK0_AFE_SETTING);
+       val32 |= 0x0f000000;
+       rtl8xxxu_write32(priv, REG_CCK0_AFE_SETTING, val32);
 
-       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_RCK_OS, 0x30000);
-       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G1, 0x0001f);
-       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_TXPA_G2, 0xf7fb7);
+       rtl8xxxu_write32(priv, REG_OFDM0_TRX_PATH_ENABLE, 0x03a05600);
+       rtl8xxxu_write32(priv, REG_OFDM0_TR_MUX_PAR, 0x000800e4);
+       rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_SW_CTRL, 0x22208200);
 
-       val32 = rtl8xxxu_read_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_ED);
-       val32 |= 0x20;
-       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_ED, val32);
+       val32 = rtl8xxxu_read32(priv, REG_FPGA0_XAB_RF_SW_CTRL);
+       val32 |= (FPGA0_RF_PAPE | (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT));
+       rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
 
-       rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_43, 0x60fbd);
+       val32 = rtl8xxxu_read32(priv, REG_FPGA0_XA_RF_INT_OE);
+       val32 |= BIT(10);
+       rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, val32);
+       val32 = rtl8xxxu_read32(priv, REG_FPGA0_XB_RF_INT_OE);
+       val32 |= BIT(10);
+       rtl8xxxu_write32(priv, REG_FPGA0_XB_RF_INT_OE, val32);
+
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+       rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
+       rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
 
        for (i = 0; i < retry; i++) {
-               path_a_ok = rtl8723bu_iqk_path_a(priv);
+               path_a_ok = rtl8192eu_iqk_path_a(priv);
                if (path_a_ok == 0x01) {
-                       val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
-                       val32 &= 0x000000ff;
-                       rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
-
-#if 0 /* Only needed in restore case, we may need this when going to suspend */
-                       priv->RFCalibrateInfo.TxLOK[RF_A] =
-                               rtl8xxxu_read_rfreg(priv, RF_A,
-                                                   RF6052_REG_TXM_IDAC);
-#endif
-
                        val32 = rtl8xxxu_read32(priv,
                                                REG_TX_POWER_BEFORE_IQK_A);
                        result[t][0] = (val32 >> 16) & 0x3ff;
@@ -4756,7 +5997,7 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
                dev_dbg(dev, "%s: Path A TX IQK failed!\n", __func__);
 
        for (i = 0; i < retry; i++) {
-               path_a_ok = rtl8723bu_rx_iqk_path_a(priv);
+               path_a_ok = rtl8192eu_rx_iqk_path_a(priv);
                if (path_a_ok == 0x03) {
                        val32 = rtl8xxxu_read32(priv,
                                                REG_RX_POWER_BEFORE_IQK_A_2);
@@ -4772,30 +6013,22 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
        if (!path_a_ok)
                dev_dbg(dev, "%s: Path A RX IQK failed!\n", __func__);
 
-       if (priv->tx_paths > 1) {
-#if 1
-               dev_warn(dev, "%s: Path B not supported\n", __func__);
-#else
-
-               /*
-                * Path A into standby
-                */
-               val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
-               val32 &= 0x000000ff;
-               rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
+       if (priv->rf_paths > 1) {
+               /* Path A into standby */
+               rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
                rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_AC, 0x10000);
-
-               val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
-               val32 &= 0x000000ff;
-               val32 |= 0x80800000;
-               rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
+               rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
 
                /* Turn Path B ADDA on */
                rtl8xxxu_path_adda_on(priv, adda_regs, false);
 
+               rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x80800000);
+               rtl8xxxu_write32(priv, REG_TX_IQK, 0x01007c00);
+               rtl8xxxu_write32(priv, REG_RX_IQK, 0x01004800);
+
                for (i = 0; i < retry; i++) {
-                       path_b_ok = rtl8xxxu_iqk_path_b(priv);
-                       if (path_b_ok == 0x03) {
+                       path_b_ok = rtl8192eu_iqk_path_b(priv);
+                       if (path_b_ok == 0x01) {
                                val32 = rtl8xxxu_read32(priv, REG_TX_POWER_BEFORE_IQK_B);
                                result[t][4] = (val32 >> 16) & 0x3ff;
                                val32 = rtl8xxxu_read32(priv, REG_TX_POWER_AFTER_IQK_B);
@@ -4808,7 +6041,7 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
                        dev_dbg(dev, "%s: Path B IQK failed!\n", __func__);
 
                for (i = 0; i < retry; i++) {
-                       path_b_ok = rtl8723bu_rx_iqk_path_b(priv);
+                       path_b_ok = rtl8192eu_rx_iqk_path_b(priv);
                        if (path_a_ok == 0x03) {
                                val32 = rtl8xxxu_read32(priv,
                                                        REG_RX_POWER_BEFORE_IQK_B_2);
@@ -4822,13 +6055,10 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
 
                if (!path_b_ok)
                        dev_dbg(dev, "%s: Path B RX IQK failed!\n", __func__);
-#endif
        }
 
        /* Back to BB mode, load original value */
-       val32 = rtl8xxxu_read32(priv, REG_FPGA0_IQK);
-       val32 &= 0x000000ff;
-       rtl8xxxu_write32(priv, REG_FPGA0_IQK, val32);
+       rtl8xxxu_write32(priv, REG_FPGA0_IQK, 0x00000000);
 
        if (t) {
                /* Reload ADDA power saving parameters */
@@ -4848,7 +6078,7 @@ static void rtl8723bu_phy_iqcalibrate(struct rtl8xxxu_priv *priv,
                rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, val32 | 0x50);
                rtl8xxxu_write32(priv, REG_OFDM0_XA_AGC_CORE1, val32 | xa_agc);
 
-               if (priv->tx_paths > 1) {
+               if (priv->rf_paths > 1) {
                        val32 = rtl8xxxu_read32(priv, REG_OFDM0_XB_AGC_CORE1);
                        val32 &= 0xffffff00;
                        rtl8xxxu_write32(priv, REG_OFDM0_XB_AGC_CORE1,
@@ -4877,7 +6107,7 @@ static void rtl8xxxu_prepare_calibrate(struct rtl8xxxu_priv *priv, u8 start)
        rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.bt_wlan_calibration));
 }
 
-static void rtl8723au_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
+static void rtl8xxxu_gen1_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
 {
        struct device *dev = &priv->udev->dev;
        int result[4][8];       /* last is final result */
@@ -4975,7 +6205,7 @@ static void rtl8723au_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
                rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result,
                                           candidate, (reg_ec4 == 0));
 
-       rtl8xxxu_save_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
+       rtl8xxxu_save_regs(priv, rtl8xxxu_iqk_phy_iq_bb_reg,
                           priv->bb_recovery_backup, RTL8XXXU_BB_REGS);
 
        rtl8xxxu_prepare_calibrate(priv, 0);
@@ -5007,7 +6237,8 @@ static void rtl8723bu_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
                rtl8723bu_phy_iqcalibrate(priv, result, i);
 
                if (i == 1) {
-                       simu = rtl8723bu_simularity_compare(priv, result, 0, 1);
+                       simu = rtl8xxxu_gen2_simularity_compare(priv,
+                                                               result, 0, 1);
                        if (simu) {
                                candidate = 0;
                                break;
@@ -5015,13 +6246,15 @@ static void rtl8723bu_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
                }
 
                if (i == 2) {
-                       simu = rtl8723bu_simularity_compare(priv, result, 0, 2);
+                       simu = rtl8xxxu_gen2_simularity_compare(priv,
+                                                               result, 0, 2);
                        if (simu) {
                                candidate = 0;
                                break;
                        }
 
-                       simu = rtl8723bu_simularity_compare(priv, result, 1, 2);
+                       simu = rtl8xxxu_gen2_simularity_compare(priv,
+                                                               result, 1, 2);
                        if (simu) {
                                candidate = 1;
                        } else {
@@ -5080,7 +6313,7 @@ static void rtl8723bu_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
                rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result,
                                           candidate, (reg_ec4 == 0));
 
-       rtl8xxxu_save_regs(priv, rtl8723au_iqk_phy_iq_bb_reg,
+       rtl8xxxu_save_regs(priv, rtl8xxxu_iqk_phy_iq_bb_reg,
                           priv->bb_recovery_backup, RTL8XXXU_BB_REGS);
 
        rtl8xxxu_write32(priv, REG_BT_CONTROL_8723BU, bt_control);
@@ -5096,18 +6329,105 @@ static void rtl8723bu_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
        rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_UNKNOWN_ED, val32);
        rtl8xxxu_write_rfreg(priv, RF_A, 0x43, 0x300bd);
 
-       if (priv->rf_paths > 1) {
-               dev_dbg(dev, "%s: beware 2T not yet supported\n", __func__);
-#ifdef RTL8723BU_PATH_B
-               if (RF_Path == 0x0)     //S1
-                       ODM_SetIQCbyRFpath(pDM_Odm, 0);
-               else    //S0
-                       ODM_SetIQCbyRFpath(pDM_Odm, 1);
-#endif
-       }
+       if (priv->rf_paths > 1)
+               dev_dbg(dev, "%s: 8723BU 2T not supported\n", __func__);
+
        rtl8xxxu_prepare_calibrate(priv, 0);
 }
 
+static void rtl8192eu_phy_iq_calibrate(struct rtl8xxxu_priv *priv)
+{
+       struct device *dev = &priv->udev->dev;
+       int result[4][8];       /* last is final result */
+       int i, candidate;
+       bool path_a_ok, path_b_ok;
+       u32 reg_e94, reg_e9c, reg_ea4, reg_eac;
+       u32 reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+       bool simu;
+
+       memset(result, 0, sizeof(result));
+       candidate = -1;
+
+       path_a_ok = false;
+       path_b_ok = false;
+
+       for (i = 0; i < 3; i++) {
+               rtl8192eu_phy_iqcalibrate(priv, result, i);
+
+               if (i == 1) {
+                       simu = rtl8xxxu_gen2_simularity_compare(priv,
+                                                               result, 0, 1);
+                       if (simu) {
+                               candidate = 0;
+                               break;
+                       }
+               }
+
+               if (i == 2) {
+                       simu = rtl8xxxu_gen2_simularity_compare(priv,
+                                                               result, 0, 2);
+                       if (simu) {
+                               candidate = 0;
+                               break;
+                       }
+
+                       simu = rtl8xxxu_gen2_simularity_compare(priv,
+                                                               result, 1, 2);
+                       if (simu)
+                               candidate = 1;
+                       else
+                               candidate = 3;
+               }
+       }
+
+       for (i = 0; i < 4; i++) {
+               reg_e94 = result[i][0];
+               reg_e9c = result[i][1];
+               reg_ea4 = result[i][2];
+               reg_eac = result[i][3];
+               reg_eb4 = result[i][4];
+               reg_ebc = result[i][5];
+               reg_ec4 = result[i][6];
+               reg_ecc = result[i][7];
+       }
+
+       if (candidate >= 0) {
+               reg_e94 = result[candidate][0];
+               priv->rege94 =  reg_e94;
+               reg_e9c = result[candidate][1];
+               priv->rege9c = reg_e9c;
+               reg_ea4 = result[candidate][2];
+               reg_eac = result[candidate][3];
+               reg_eb4 = result[candidate][4];
+               priv->regeb4 = reg_eb4;
+               reg_ebc = result[candidate][5];
+               priv->regebc = reg_ebc;
+               reg_ec4 = result[candidate][6];
+               reg_ecc = result[candidate][7];
+               dev_dbg(dev, "%s: candidate is %x\n", __func__, candidate);
+               dev_dbg(dev,
+                       "%s: e94 =%x e9c=%x ea4=%x eac=%x eb4=%x ebc=%x ec4=%x "
+                       "ecc=%x\n ", __func__, reg_e94, reg_e9c,
+                       reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc);
+               path_a_ok = true;
+               path_b_ok = true;
+       } else {
+               reg_e94 = reg_eb4 = priv->rege94 = priv->regeb4 = 0x100;
+               reg_e9c = reg_ebc = priv->rege9c = priv->regebc = 0x0;
+       }
+
+       if (reg_e94 && candidate >= 0)
+               rtl8xxxu_fill_iqk_matrix_a(priv, path_a_ok, result,
+                                          candidate, (reg_ea4 == 0));
+
+       if (priv->rf_paths > 1)
+               rtl8xxxu_fill_iqk_matrix_b(priv, path_b_ok, result,
+                                          candidate, (reg_ec4 == 0));
+
+       rtl8xxxu_save_regs(priv, rtl8xxxu_iqk_phy_iq_bb_reg,
+                          priv->bb_recovery_backup, RTL8XXXU_BB_REGS);
+}
+
 static void rtl8723a_phy_lc_calibrate(struct rtl8xxxu_priv *priv)
 {
        u32 val32;
@@ -5231,7 +6551,7 @@ static void rtl8xxxu_set_ampdu_min_space(struct rtl8xxxu_priv *priv, u8 density)
 static int rtl8xxxu_active_to_emu(struct rtl8xxxu_priv *priv)
 {
        u8 val8;
-       int count, ret;
+       int count, ret = 0;
 
        /* Start of rtl8723AU_card_enable_flow */
        /* Act to Cardemu sequence*/
@@ -5281,7 +6601,7 @@ static int rtl8723bu_active_to_emu(struct rtl8xxxu_priv *priv)
        u8 val8;
        u16 val16;
        u32 val32;
-       int count, ret;
+       int count, ret = 0;
 
        /* Turn off RF */
        rtl8xxxu_write8(priv, REG_RF_CTRL, 0);
@@ -5292,9 +6612,9 @@ static int rtl8723bu_active_to_emu(struct rtl8xxxu_priv *priv)
        rtl8xxxu_write16(priv, REG_GPIO_INTM, val16);
 
        /* Release WLON reset 0x04[16]= 1*/
-       val32 = rtl8xxxu_read32(priv, REG_GPIO_INTM);
+       val32 = rtl8xxxu_read32(priv, REG_APS_FSMCO);
        val32 |= APS_FSMCO_WLON_RESET;
-       rtl8xxxu_write32(priv, REG_GPIO_INTM, val32);
+       rtl8xxxu_write32(priv, REG_APS_FSMCO, val32);
 
        /* 0x0005[1] = 1 turn off MAC by HW state machine*/
        val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
@@ -5338,7 +6658,7 @@ static int rtl8xxxu_active_to_lps(struct rtl8xxxu_priv *priv)
 {
        u8 val8;
        u8 val32;
-       int count, ret;
+       int count, ret = 0;
 
        rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
 
@@ -5756,6 +7076,50 @@ static int rtl8xxxu_flush_fifo(struct rtl8xxxu_priv *priv)
        return retval;
 }
 
+static void rtl8xxxu_gen1_usb_quirks(struct rtl8xxxu_priv *priv)
+{
+       /* Fix USB interface interference issue */
+       rtl8xxxu_write8(priv, 0xfe40, 0xe0);
+       rtl8xxxu_write8(priv, 0xfe41, 0x8d);
+       rtl8xxxu_write8(priv, 0xfe42, 0x80);
+       /*
+        * This sets TXDMA_OFFSET_DROP_DATA_EN (bit 9) as well as bits
+        * 8 and 5, for which I have found no documentation.
+        */
+       rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320);
+
+       /*
+        * Solve too many protocol error on USB bus.
+        * Can't do this for 8188/8192 UMC A cut parts
+        */
+       if (!(!priv->chip_cut && priv->vendor_umc)) {
+               rtl8xxxu_write8(priv, 0xfe40, 0xe6);
+               rtl8xxxu_write8(priv, 0xfe41, 0x94);
+               rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+               rtl8xxxu_write8(priv, 0xfe40, 0xe0);
+               rtl8xxxu_write8(priv, 0xfe41, 0x19);
+               rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+               rtl8xxxu_write8(priv, 0xfe40, 0xe5);
+               rtl8xxxu_write8(priv, 0xfe41, 0x91);
+               rtl8xxxu_write8(priv, 0xfe42, 0x80);
+
+               rtl8xxxu_write8(priv, 0xfe40, 0xe2);
+               rtl8xxxu_write8(priv, 0xfe41, 0x81);
+               rtl8xxxu_write8(priv, 0xfe42, 0x80);
+       }
+}
+
+static void rtl8xxxu_gen2_usb_quirks(struct rtl8xxxu_priv *priv)
+{
+       u32 val32;
+
+       val32 = rtl8xxxu_read32(priv, REG_TXDMA_OFFSET_CHK);
+       val32 |= TXDMA_OFFSET_DROP_DATA_EN;
+       rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32);
+}
+
 static int rtl8723au_power_on(struct rtl8xxxu_priv *priv)
 {
        u8 val8;
@@ -5952,10 +7316,12 @@ static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv)
                CR_SCHEDULE_ENABLE | CR_MAC_TX_ENABLE | CR_MAC_RX_ENABLE;
        rtl8xxxu_write16(priv, REG_CR, val16);
 
+       rtl8xxxu_write8(priv, 0xfe10, 0x19);
+
        /*
         * Workaround for 8188RU LNA power leakage problem.
         */
-       if (priv->rtl_chip == RTL8188C && priv->hi_pa) {
+       if (priv->rtl_chip == RTL8188R) {
                val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
                val32 &= ~BIT(1);
                rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
@@ -5965,6 +7331,41 @@ static int rtl8192cu_power_on(struct rtl8xxxu_priv *priv)
 
 #endif
 
+/*
+ * This is needed for 8723bu as well, presumable
+ */
+static void rtl8192e_crystal_afe_adjust(struct rtl8xxxu_priv *priv)
+{
+       u8 val8;
+       u32 val32;
+
+       /*
+        * 40Mhz crystal source, MAC 0x28[2]=0
+        */
+       val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL);
+       val8 &= 0xfb;
+       rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8);
+
+       val32 = rtl8xxxu_read32(priv, REG_AFE_CTRL4);
+       val32 &= 0xfffffc7f;
+       rtl8xxxu_write32(priv, REG_AFE_CTRL4, val32);
+
+       /*
+        * 92e AFE parameter
+        * AFE PLL KVCO selection, MAC 0x28[6]=1
+        */
+       val8 = rtl8xxxu_read8(priv, REG_AFE_PLL_CTRL);
+       val8 &= 0xbf;
+       rtl8xxxu_write8(priv, REG_AFE_PLL_CTRL, val8);
+
+       /*
+        * AFE PLL KVCO selection, MAC 0x78[21]=0
+        */
+       val32 = rtl8xxxu_read32(priv, REG_AFE_CTRL4);
+       val32 &= 0xffdfffff;
+       rtl8xxxu_write32(priv, REG_AFE_CTRL4, val32);
+}
+
 static int rtl8192eu_power_on(struct rtl8xxxu_priv *priv)
 {
        u16 val16;
@@ -5987,6 +7388,10 @@ static int rtl8192eu_power_on(struct rtl8xxxu_priv *priv)
                rtl8xxxu_write8(priv, REG_LDO_SW_CTRL, 0x83);
        }
 
+       /*
+        * Adjust AFE before enabling PLL
+        */
+       rtl8192e_crystal_afe_adjust(priv);
        rtl8192e_disabled_to_emu(priv);
 
        ret = rtl8192e_emu_to_active(priv);
@@ -6020,7 +7425,7 @@ static void rtl8xxxu_power_off(struct rtl8xxxu_priv *priv)
        /*
         * Workaround for 8188RU LNA power leakage problem.
         */
-       if (priv->rtl_chip == RTL8188C && priv->hi_pa) {
+       if (priv->rtl_chip == RTL8188R) {
                val32 = rtl8xxxu_read32(priv, REG_FPGA0_XCD_RF_PARM);
                val32 |= BIT(1);
                rtl8xxxu_write32(priv, REG_FPGA0_XCD_RF_PARM, val32);
@@ -6075,7 +7480,7 @@ static void rtl8723bu_power_off(struct rtl8xxxu_priv *priv)
        val8 &= ~TX_REPORT_CTRL_TIMER_ENABLE;
        rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8);
 
-       rtl8xxxu_write16(priv, REG_CR, 0x0000);
+       rtl8xxxu_write8(priv, REG_CR, 0x0000);
 
        rtl8xxxu_active_to_lps(priv);
 
@@ -6092,7 +7497,15 @@ static void rtl8723bu_power_off(struct rtl8xxxu_priv *priv)
        rtl8xxxu_write8(priv, REG_MCU_FW_DL, 0x00);
 
        rtl8723bu_active_to_emu(priv);
-       rtl8xxxu_emu_to_disabled(priv);
+
+       val8 = rtl8xxxu_read8(priv, REG_APS_FSMCO + 1);
+       val8 |= BIT(3); /* APS_FSMCO_HW_SUSPEND */
+       rtl8xxxu_write8(priv, REG_APS_FSMCO + 1, val8);
+
+       /* 0x48[16] = 1 to enable GPIO9 as EXT wakeup */
+       val8 = rtl8xxxu_read8(priv, REG_GPIO_INTM + 2);
+       val8 |= BIT(0);
+       rtl8xxxu_write8(priv, REG_GPIO_INTM + 2, val8);
 }
 
 #ifdef NEED_PS_TDMA
@@ -6101,16 +7514,53 @@ static void rtl8723bu_set_ps_tdma(struct rtl8xxxu_priv *priv,
 {
        struct h2c_cmd h2c;
 
-       memset(&h2c, 0, sizeof(struct h2c_cmd));
-       h2c.b_type_dma.cmd = H2C_8723B_B_TYPE_TDMA;
-       h2c.b_type_dma.data1 = arg1;
-       h2c.b_type_dma.data2 = arg2;
-       h2c.b_type_dma.data3 = arg3;
-       h2c.b_type_dma.data4 = arg4;
-       h2c.b_type_dma.data5 = arg5;
-       rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.b_type_dma));
+       memset(&h2c, 0, sizeof(struct h2c_cmd));
+       h2c.b_type_dma.cmd = H2C_8723B_B_TYPE_TDMA;
+       h2c.b_type_dma.data1 = arg1;
+       h2c.b_type_dma.data2 = arg2;
+       h2c.b_type_dma.data3 = arg3;
+       h2c.b_type_dma.data4 = arg4;
+       h2c.b_type_dma.data5 = arg5;
+       rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.b_type_dma));
+}
+#endif
+
+static void rtl8192e_enable_rf(struct rtl8xxxu_priv *priv)
+{
+       u32 val32;
+       u8 val8;
+
+       val8 = rtl8xxxu_read8(priv, REG_GPIO_MUXCFG);
+       val8 |= BIT(5);
+       rtl8xxxu_write8(priv, REG_GPIO_MUXCFG, val8);
+
+       /*
+        * WLAN action by PTA
+        */
+       rtl8xxxu_write8(priv, REG_WLAN_ACT_CONTROL_8723B, 0x04);
+
+       val32 = rtl8xxxu_read32(priv, REG_PWR_DATA);
+       val32 |= PWR_DATA_EEPRPAD_RFE_CTRL_EN;
+       rtl8xxxu_write32(priv, REG_PWR_DATA, val32);
+
+       val32 = rtl8xxxu_read32(priv, REG_RFE_BUFFER);
+       val32 |= (BIT(0) | BIT(1));
+       rtl8xxxu_write32(priv, REG_RFE_BUFFER, val32);
+
+       rtl8xxxu_write8(priv, REG_RFE_CTRL_ANTA_SRC, 0x77);
+
+       val32 = rtl8xxxu_read32(priv, REG_LEDCFG0);
+       val32 &= ~BIT(24);
+       val32 |= BIT(23);
+       rtl8xxxu_write32(priv, REG_LEDCFG0, val32);
+
+       /*
+        * Fix external switch Main->S1, Aux->S0
+        */
+       val8 = rtl8xxxu_read8(priv, REG_PAD_CTRL1);
+       val8 &= ~BIT(0);
+       rtl8xxxu_write8(priv, REG_PAD_CTRL1, val8);
 }
-#endif
 
 static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv)
 {
@@ -6219,12 +7669,10 @@ static void rtl8723b_enable_rf(struct rtl8xxxu_priv *priv)
        rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ignore_wlan));
 }
 
-static void rtl8723b_disable_rf(struct rtl8xxxu_priv *priv)
+static void rtl8xxxu_gen2_disable_rf(struct rtl8xxxu_priv *priv)
 {
        u32 val32;
 
-       rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
-
        val32 = rtl8xxxu_read32(priv, REG_RX_WAIT_CCA);
        val32 &= ~(BIT(22) | BIT(23));
        rtl8xxxu_write32(priv, REG_RX_WAIT_CCA, val32);
@@ -6272,11 +7720,64 @@ static void rtl8723bu_init_statistics(struct rtl8xxxu_priv *priv)
        rtl8xxxu_write32(priv, REG_OFDM0_FA_RSTC, val32);
 }
 
+static void rtl8xxxu_old_init_queue_reserved_page(struct rtl8xxxu_priv *priv)
+{
+       u8 val8;
+       u32 val32;
+
+       if (priv->ep_tx_normal_queue)
+               val8 = TX_PAGE_NUM_NORM_PQ;
+       else
+               val8 = 0;
+
+       rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8);
+
+       val32 = (TX_PAGE_NUM_PUBQ << RQPN_PUB_PQ_SHIFT) | RQPN_LOAD;
+
+       if (priv->ep_tx_high_queue)
+               val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT);
+       if (priv->ep_tx_low_queue)
+               val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT);
+
+       rtl8xxxu_write32(priv, REG_RQPN, val32);
+}
+
+static void rtl8xxxu_init_queue_reserved_page(struct rtl8xxxu_priv *priv)
+{
+       struct rtl8xxxu_fileops *fops = priv->fops;
+       u32 hq, lq, nq, eq, pubq;
+       u32 val32;
+
+       hq = 0;
+       lq = 0;
+       nq = 0;
+       eq = 0;
+       pubq = 0;
+
+       if (priv->ep_tx_high_queue)
+               hq = fops->page_num_hi;
+       if (priv->ep_tx_low_queue)
+               lq = fops->page_num_lo;
+       if (priv->ep_tx_normal_queue)
+               nq = fops->page_num_norm;
+
+       val32 = (nq << RQPN_NPQ_SHIFT) | (eq << RQPN_EPQ_SHIFT);
+       rtl8xxxu_write32(priv, REG_RQPN_NPQ, val32);
+
+       pubq = fops->total_page_num - hq - lq - nq;
+
+       val32 = RQPN_LOAD;
+       val32 |= (hq << RQPN_HI_PQ_SHIFT);
+       val32 |= (lq << RQPN_LO_PQ_SHIFT);
+       val32 |= (pubq << RQPN_PUB_PQ_SHIFT);
+
+       rtl8xxxu_write32(priv, REG_RQPN, val32);
+}
+
 static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
 {
        struct rtl8xxxu_priv *priv = hw->priv;
        struct device *dev = &priv->udev->dev;
-       struct rtl8xxxu_rfregval *rftable;
        bool macpower;
        int ret;
        u8 val8;
@@ -6301,33 +7802,22 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
                goto exit;
        }
 
-       dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
        if (!macpower) {
-               ret = priv->fops->llt_init(priv, TX_TOTAL_PAGE_NUM);
-               if (ret) {
-                       dev_warn(dev, "%s: LLT table init failed\n", __func__);
-                       goto exit;
-               }
+               if (priv->fops->total_page_num)
+                       rtl8xxxu_init_queue_reserved_page(priv);
+               else
+                       rtl8xxxu_old_init_queue_reserved_page(priv);
+       }
 
-               /*
-                * Presumably this is for 8188EU as well
-                * Enable TX report and TX report timer
-                */
-               if (priv->rtl_chip == RTL8723B) {
-                       val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL);
-                       val8 |= TX_REPORT_CTRL_TIMER_ENABLE;
-                       rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8);
-                       /* Set MAX RPT MACID */
-                       rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL + 1, 0x02);
-                       /* TX report Timer. Unit: 32us */
-                       rtl8xxxu_write16(priv, REG_TX_REPORT_TIME, 0xcdf0);
+       ret = rtl8xxxu_init_queue_priority(priv);
+       dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret);
+       if (ret)
+               goto exit;
 
-                       /* tmp ps ? */
-                       val8 = rtl8xxxu_read8(priv, 0xa3);
-                       val8 &= 0xf8;
-                       rtl8xxxu_write8(priv, 0xa3, val8);
-               }
-       }
+       /*
+        * Set RX page boundary
+        */
+       rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, priv->fops->trxff_boundary);
 
        ret = rtl8xxxu_download_firmware(priv);
        dev_dbg(dev, "%s: download_fiwmare %i\n", __func__, ret);
@@ -6338,41 +7828,10 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
        if (ret)
                goto exit;
 
-       /* Solve too many protocol error on USB bus */
-       /* Can't do this for 8188/8192 UMC A cut parts */
-       if (priv->rtl_chip == RTL8723A ||
-           ((priv->rtl_chip == RTL8192C || priv->rtl_chip == RTL8191C ||
-             priv->rtl_chip == RTL8188C) &&
-            (priv->chip_cut || !priv->vendor_umc))) {
-               rtl8xxxu_write8(priv, 0xfe40, 0xe6);
-               rtl8xxxu_write8(priv, 0xfe41, 0x94);
-               rtl8xxxu_write8(priv, 0xfe42, 0x80);
-
-               rtl8xxxu_write8(priv, 0xfe40, 0xe0);
-               rtl8xxxu_write8(priv, 0xfe41, 0x19);
-               rtl8xxxu_write8(priv, 0xfe42, 0x80);
-
-               rtl8xxxu_write8(priv, 0xfe40, 0xe5);
-               rtl8xxxu_write8(priv, 0xfe41, 0x91);
-               rtl8xxxu_write8(priv, 0xfe42, 0x80);
-
-               rtl8xxxu_write8(priv, 0xfe40, 0xe2);
-               rtl8xxxu_write8(priv, 0xfe41, 0x81);
-               rtl8xxxu_write8(priv, 0xfe42, 0x80);
-       }
-
-       if (priv->rtl_chip == RTL8192E) {
-               rtl8xxxu_write32(priv, REG_HIMR0, 0x00);
-               rtl8xxxu_write32(priv, REG_HIMR1, 0x00);
-       }
-
        if (priv->fops->phy_init_antenna_selection)
                priv->fops->phy_init_antenna_selection(priv);
 
-       if (priv->rtl_chip == RTL8723B)
-               ret = rtl8xxxu_init_mac(priv, rtl8723b_mac_init_table);
-       else
-               ret = rtl8xxxu_init_mac(priv, rtl8723a_mac_init_table);
+       ret = rtl8xxxu_init_mac(priv);
 
        dev_dbg(dev, "%s: init_mac %i\n", __func__, ret);
        if (ret)
@@ -6383,90 +7842,35 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
        if (ret)
                goto exit;
 
-       switch(priv->rtl_chip) {
-       case RTL8723A:
-               rftable = rtl8723au_radioa_1t_init_table;
-               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
-               break;
-       case RTL8723B:
-               rftable = rtl8723bu_radioa_1t_init_table;
-               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
-               /*
-                * PHY LCK
-                */
-               rtl8xxxu_write_rfreg(priv, RF_A, 0xb0, 0xdfbe0);
-               rtl8xxxu_write_rfreg(priv, RF_A, RF6052_REG_MODE_AG, 0x8c01);
-               msleep(200);
-               rtl8xxxu_write_rfreg(priv, RF_A, 0xb0, 0xdffe0);
-               break;
-       case RTL8188C:
-               if (priv->hi_pa)
-                       rftable = rtl8188ru_radioa_1t_highpa_table;
-               else
-                       rftable = rtl8192cu_radioa_1t_init_table;
-               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
-               break;
-       case RTL8191C:
-               rftable = rtl8192cu_radioa_1t_init_table;
-               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
-               break;
-       case RTL8192C:
-               rftable = rtl8192cu_radioa_2t_init_table;
-               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_A);
-               if (ret)
-                       break;
-               rftable = rtl8192cu_radiob_2t_init_table;
-               ret = rtl8xxxu_init_phy_rf(priv, rftable, RF_B);
-               break;
-       default:
-               ret = -EINVAL;
-       }
-
+       ret = priv->fops->init_phy_rf(priv);
        if (ret)
                goto exit;
 
-       /*
-        * Chip specific quirks
-        */
-       if (priv->rtl_chip == RTL8723A) {
-               /* Fix USB interface interference issue */
-               rtl8xxxu_write8(priv, 0xfe40, 0xe0);
-               rtl8xxxu_write8(priv, 0xfe41, 0x8d);
-               rtl8xxxu_write8(priv, 0xfe42, 0x80);
-               rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, 0xfd0320);
+       /* RFSW Control - clear bit 14 ?? */
+       if (priv->rtl_chip != RTL8723B && priv->rtl_chip != RTL8192E)
+               rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003);
 
-               /* Reduce 80M spur */
-               rtl8xxxu_write32(priv, REG_AFE_XTAL_CTRL, 0x0381808d);
-               rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
-               rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff82);
-               rtl8xxxu_write32(priv, REG_AFE_PLL_CTRL, 0xf0ffff83);
-       } else {
-               val32 = rtl8xxxu_read32(priv, REG_TXDMA_OFFSET_CHK);
-               val32 |= TXDMA_OFFSET_DROP_DATA_EN;
-               rtl8xxxu_write32(priv, REG_TXDMA_OFFSET_CHK, val32);
+       val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW |
+               FPGA0_RF_ANTSWB |
+               ((FPGA0_RF_ANTSW | FPGA0_RF_ANTSWB) << FPGA0_RF_BD_CTRL_SHIFT);
+       if (!priv->no_pape) {
+               val32 |= (FPGA0_RF_PAPE |
+                         (FPGA0_RF_PAPE << FPGA0_RF_BD_CTRL_SHIFT));
        }
+       rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
 
-       if (!macpower) {
-               if (priv->ep_tx_normal_queue)
-                       val8 = TX_PAGE_NUM_NORM_PQ;
-               else
-                       val8 = 0;
-
-               rtl8xxxu_write8(priv, REG_RQPN_NPQ, val8);
-
-               val32 = (TX_PAGE_NUM_PUBQ << RQPN_NORM_PQ_SHIFT) | RQPN_LOAD;
-
-               if (priv->ep_tx_high_queue)
-                       val32 |= (TX_PAGE_NUM_HI_PQ << RQPN_HI_PQ_SHIFT);
-               if (priv->ep_tx_low_queue)
-                       val32 |= (TX_PAGE_NUM_LO_PQ << RQPN_LO_PQ_SHIFT);
-
-               rtl8xxxu_write32(priv, REG_RQPN, val32);
+       /* 0x860[6:5]= 00 - why? - this sets antenna B */
+       if (priv->rtl_chip != RTL8192E)
+               rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66f60210);
 
+       if (!macpower) {
                /*
                 * Set TX buffer boundary
                 */
-               val8 = TX_TOTAL_PAGE_NUM + 1;
+               if (priv->rtl_chip == RTL8192E)
+                       val8 = TX_TOTAL_PAGE_NUM_8192E + 1;
+               else
+                       val8 = TX_TOTAL_PAGE_NUM + 1;
 
                if (priv->rtl_chip == RTL8723B)
                        val8 -= 1;
@@ -6478,54 +7882,63 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
                rtl8xxxu_write8(priv, REG_TDECTRL + 1, val8);
        }
 
-       ret = rtl8xxxu_init_queue_priority(priv);
-       dev_dbg(dev, "%s: init_queue_priority %i\n", __func__, ret);
-       if (ret)
-               goto exit;
+       /*
+        * The vendor drivers set PBP for all devices, except 8192e.
+        * There is no explanation for this in any of the sources.
+        */
+       val8 = (priv->fops->pbp_rx << PBP_PAGE_SIZE_RX_SHIFT) |
+               (priv->fops->pbp_tx << PBP_PAGE_SIZE_TX_SHIFT);
+       if (priv->rtl_chip != RTL8192E)
+               rtl8xxxu_write8(priv, REG_PBP, val8);
 
-       /* RFSW Control - clear bit 14 ?? */
-       if (priv->rtl_chip != RTL8723B)
-               rtl8xxxu_write32(priv, REG_FPGA0_TX_INFO, 0x00000003);
-       /* 0x07000760 */
-       val32 = FPGA0_RF_TRSW | FPGA0_RF_TRSWB | FPGA0_RF_ANTSW |
-               FPGA0_RF_ANTSWB | FPGA0_RF_PAPE |
-               ((FPGA0_RF_ANTSW | FPGA0_RF_ANTSWB | FPGA0_RF_PAPE) <<
-                FPGA0_RF_BD_CTRL_SHIFT);
-       rtl8xxxu_write32(priv, REG_FPGA0_XAB_RF_SW_CTRL, val32);
-       /* 0x860[6:5]= 00 - why? - this sets antenna B */
-       rtl8xxxu_write32(priv, REG_FPGA0_XA_RF_INT_OE, 0x66F60210);
+       dev_dbg(dev, "%s: macpower %i\n", __func__, macpower);
+       if (!macpower) {
+               ret = priv->fops->llt_init(priv, TX_TOTAL_PAGE_NUM);
+               if (ret) {
+                       dev_warn(dev, "%s: LLT table init failed\n", __func__);
+                       goto exit;
+               }
 
-       priv->rf_mode_ag[0] = rtl8xxxu_read_rfreg(priv, RF_A,
-                                                 RF6052_REG_MODE_AG);
+               /*
+                * Chip specific quirks
+                */
+               priv->fops->usb_quirks(priv);
 
-       /*
-        * Set RX page boundary
-        */
-       if (priv->rtl_chip == RTL8723B)
-               rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x3f7f);
-       else
-               rtl8xxxu_write16(priv, REG_TRXFF_BNDY + 2, 0x27ff);
-       /*
-        * Transfer page size is always 128
-        */
-       if (priv->rtl_chip == RTL8723B)
-               val8 = (PBP_PAGE_SIZE_256 << PBP_PAGE_SIZE_RX_SHIFT) |
-                       (PBP_PAGE_SIZE_256 << PBP_PAGE_SIZE_TX_SHIFT);
-       else
-               val8 = (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_RX_SHIFT) |
-                       (PBP_PAGE_SIZE_128 << PBP_PAGE_SIZE_TX_SHIFT);
-       rtl8xxxu_write8(priv, REG_PBP, val8);
+               /*
+                * Presumably this is for 8188EU as well
+                * Enable TX report and TX report timer
+                */
+               if (priv->rtl_chip == RTL8723B) {
+                       val8 = rtl8xxxu_read8(priv, REG_TX_REPORT_CTRL);
+                       val8 |= TX_REPORT_CTRL_TIMER_ENABLE;
+                       rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL, val8);
+                       /* Set MAX RPT MACID */
+                       rtl8xxxu_write8(priv, REG_TX_REPORT_CTRL + 1, 0x02);
+                       /* TX report Timer. Unit: 32us */
+                       rtl8xxxu_write16(priv, REG_TX_REPORT_TIME, 0xcdf0);
+
+                       /* tmp ps ? */
+                       val8 = rtl8xxxu_read8(priv, 0xa3);
+                       val8 &= 0xf8;
+                       rtl8xxxu_write8(priv, 0xa3, val8);
+               }
+       }
 
        /*
         * Unit in 8 bytes, not obvious what it is used for
         */
        rtl8xxxu_write8(priv, REG_RX_DRVINFO_SZ, 4);
 
-       /*
-        * Enable all interrupts - not obvious USB needs to do this
-        */
-       rtl8xxxu_write32(priv, REG_HISR, 0xffffffff);
-       rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff);
+       if (priv->rtl_chip == RTL8192E) {
+               rtl8xxxu_write32(priv, REG_HIMR0, 0x00);
+               rtl8xxxu_write32(priv, REG_HIMR1, 0x00);
+       } else {
+               /*
+                * Enable all interrupts - not obvious USB needs to do this
+                */
+               rtl8xxxu_write32(priv, REG_HISR, 0xffffffff);
+               rtl8xxxu_write32(priv, REG_HIMR, 0xffffffff);
+       }
 
        rtl8xxxu_set_mac(priv);
        rtl8xxxu_set_linktype(priv, NL80211_IFTYPE_STATION);
@@ -6651,9 +8064,11 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
        priv->fops->set_tx_power(priv, 1, false);
 
        /* Let the 8051 take control of antenna setting */
-       val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
-       val8 |= LEDCFG2_DPDT_SELECT;
-       rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+       if (priv->rtl_chip != RTL8192E) {
+               val8 = rtl8xxxu_read8(priv, REG_LEDCFG2);
+               val8 |= LEDCFG2_DPDT_SELECT;
+               rtl8xxxu_write8(priv, REG_LEDCFG2, val8);
+       }
 
        rtl8xxxu_write8(priv, REG_HWSEQ_CTRL, 0xff);
 
@@ -6665,6 +8080,20 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
        if (priv->fops->init_statistics)
                priv->fops->init_statistics(priv);
 
+       if (priv->rtl_chip == RTL8192E) {
+               /*
+                * 0x4c6[3] 1: RTS BW = Data BW
+                * 0: RTS BW depends on CCA / secondary CCA result.
+                */
+               val8 = rtl8xxxu_read8(priv, REG_QUEUE_CTRL);
+               val8 &= ~BIT(3);
+               rtl8xxxu_write8(priv, REG_QUEUE_CTRL, val8);
+               /*
+                * Reset USB mode switch setting
+                */
+               rtl8xxxu_write8(priv, REG_ACLK_MON, 0x00);
+       }
+
        rtl8723a_phy_lc_calibrate(priv);
 
        priv->fops->phy_iq_calibrate(priv);
@@ -6672,7 +8101,7 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
        /*
         * This should enable thermal meter
         */
-       if (priv->fops->has_s0s1)
+       if (priv->fops->tx_desc_size == sizeof(struct rtl8xxxu_txdesc40))
                rtl8xxxu_write_rfreg(priv,
                                     RF_A, RF6052_REG_T_METER_8723B, 0x37cf8);
        else
@@ -6693,6 +8122,8 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
                        val32 |= FPGA_RF_MODE_CCK;
                        rtl8xxxu_write32(priv, REG_FPGA0_RF_MODE, val32);
                }
+       } else if (priv->rtl_chip == RTL8192E) {
+               rtl8xxxu_write8(priv, REG_USB_HRPWM, 0x00);
        }
 
        val32 = rtl8xxxu_read32(priv, REG_FWHW_TXQ_CTRL);
@@ -6700,17 +8131,20 @@ static int rtl8xxxu_init_device(struct ieee80211_hw *hw)
        /* ack for xmit mgmt frames. */
        rtl8xxxu_write32(priv, REG_FWHW_TXQ_CTRL, val32);
 
+       if (priv->rtl_chip == RTL8192E) {
+               /*
+                * Fix LDPC rx hang issue.
+                */
+               val32 = rtl8xxxu_read32(priv, REG_AFE_MISC);
+               rtl8xxxu_write8(priv, REG_8192E_LDOV12_CTRL, 0x75);
+               val32 &= 0xfff00fff;
+               val32 |= 0x0007e000;
+               rtl8xxxu_write32(priv, REG_AFE_MISC, val32);
+       }
 exit:
        return ret;
 }
 
-static void rtl8xxxu_disable_device(struct ieee80211_hw *hw)
-{
-       struct rtl8xxxu_priv *priv = hw->priv;
-
-       priv->fops->power_off(priv);
-}
-
 static void rtl8xxxu_cam_write(struct rtl8xxxu_priv *priv,
                               struct ieee80211_key_conf *key, const u8 *mac)
 {
@@ -6775,8 +8209,8 @@ static void rtl8xxxu_sw_scan_complete(struct ieee80211_hw *hw,
        rtl8xxxu_write8(priv, REG_BEACON_CTRL, val8);
 }
 
-static void rtl8723au_update_rate_mask(struct rtl8xxxu_priv *priv,
-                                      u32 ramask, int sgi)
+static void rtl8xxxu_update_rate_mask(struct rtl8xxxu_priv *priv,
+                                     u32 ramask, int sgi)
 {
        struct h2c_cmd h2c;
 
@@ -6795,8 +8229,8 @@ static void rtl8723au_update_rate_mask(struct rtl8xxxu_priv *priv,
        rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.ramask));
 }
 
-static void rtl8723bu_update_rate_mask(struct rtl8xxxu_priv *priv,
-                                      u32 ramask, int sgi)
+static void rtl8xxxu_gen2_update_rate_mask(struct rtl8xxxu_priv *priv,
+                                          u32 ramask, int sgi)
 {
        struct h2c_cmd h2c;
        u8 bw = 0;
@@ -6821,8 +8255,8 @@ static void rtl8723bu_update_rate_mask(struct rtl8xxxu_priv *priv,
        rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.b_macid_cfg));
 }
 
-static void rtl8723au_report_connect(struct rtl8xxxu_priv *priv,
-                                    u8 macid, bool connect)
+static void rtl8xxxu_gen1_report_connect(struct rtl8xxxu_priv *priv,
+                                        u8 macid, bool connect)
 {
        struct h2c_cmd h2c;
 
@@ -6838,8 +8272,8 @@ static void rtl8723au_report_connect(struct rtl8xxxu_priv *priv,
        rtl8723a_h2c_cmd(priv, &h2c, sizeof(h2c.joinbss));
 }
 
-static void rtl8723bu_report_connect(struct rtl8xxxu_priv *priv,
-                                    u8 macid, bool connect)
+static void rtl8xxxu_gen2_report_connect(struct rtl8xxxu_priv *priv,
+                                        u8 macid, bool connect)
 {
        struct h2c_cmd h2c;
 
@@ -7492,15 +8926,22 @@ static void rtl8xxxu_rx_urb_work(struct work_struct *work)
        }
 }
 
-static int rtl8723au_parse_rx_desc(struct rtl8xxxu_priv *priv,
+static int rtl8xxxu_parse_rxdesc16(struct rtl8xxxu_priv *priv,
                                   struct sk_buff *skb,
                                   struct ieee80211_rx_status *rx_status)
 {
-       struct rtl8xxxu_rx_desc *rx_desc = (struct rtl8xxxu_rx_desc *)skb->data;
+       struct rtl8xxxu_rxdesc16 *rx_desc =
+               (struct rtl8xxxu_rxdesc16 *)skb->data;
        struct rtl8723au_phy_stats *phy_stats;
+       __le32 *_rx_desc_le = (__le32 *)skb->data;
+       u32 *_rx_desc = (u32 *)skb->data;
        int drvinfo_sz, desc_shift;
+       int i;
+
+       for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc16) / sizeof(u32)); i++)
+               _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
 
-       skb_pull(skb, sizeof(struct rtl8xxxu_rx_desc));
+       skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc16));
 
        phy_stats = (struct rtl8723au_phy_stats *)skb->data;
 
@@ -7532,16 +8973,22 @@ static int rtl8723au_parse_rx_desc(struct rtl8xxxu_priv *priv,
        return RX_TYPE_DATA_PKT;
 }
 
-static int rtl8723bu_parse_rx_desc(struct rtl8xxxu_priv *priv,
+static int rtl8xxxu_parse_rxdesc24(struct rtl8xxxu_priv *priv,
                                   struct sk_buff *skb,
                                   struct ieee80211_rx_status *rx_status)
 {
-       struct rtl8723bu_rx_desc *rx_desc =
-               (struct rtl8723bu_rx_desc *)skb->data;
+       struct rtl8xxxu_rxdesc24 *rx_desc =
+               (struct rtl8xxxu_rxdesc24 *)skb->data;
        struct rtl8723au_phy_stats *phy_stats;
+       __le32 *_rx_desc_le = (__le32 *)skb->data;
+       u32 *_rx_desc = (u32 *)skb->data;
        int drvinfo_sz, desc_shift;
+       int i;
+
+       for (i = 0; i < (sizeof(struct rtl8xxxu_rxdesc24) / sizeof(u32)); i++)
+               _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
 
-       skb_pull(skb, sizeof(struct rtl8723bu_rx_desc));
+       skb_pull(skb, sizeof(struct rtl8xxxu_rxdesc24));
 
        phy_stats = (struct rtl8723au_phy_stats *)skb->data;
 
@@ -7633,12 +9080,7 @@ static void rtl8xxxu_rx_complete(struct urb *urb)
        struct sk_buff *skb = (struct sk_buff *)urb->context;
        struct ieee80211_rx_status *rx_status = IEEE80211_SKB_RXCB(skb);
        struct device *dev = &priv->udev->dev;
-       __le32 *_rx_desc_le = (__le32 *)skb->data;
-       u32 *_rx_desc = (u32 *)skb->data;
-       int rx_type, i;
-
-       for (i = 0; i < (sizeof(struct rtl8xxxu_rx_desc) / sizeof(u32)); i++)
-               _rx_desc[i] = le32_to_cpu(_rx_desc_le[i]);
+       int rx_type;
 
        skb_put(skb, urb->actual_length);
 
@@ -7677,14 +9119,15 @@ static int rtl8xxxu_submit_rx_urb(struct rtl8xxxu_priv *priv,
 {
        struct sk_buff *skb;
        int skb_size;
-       int ret;
+       int ret, rx_desc_sz;
 
-       skb_size = sizeof(struct rtl8xxxu_rx_desc) + RTL_RX_BUFFER_SIZE;
+       rx_desc_sz = priv->fops->rx_desc_size;
+       skb_size = rx_desc_sz + RTL_RX_BUFFER_SIZE;
        skb = __netdev_alloc_skb(NULL, skb_size, GFP_KERNEL);
        if (!skb)
                return -ENOMEM;
 
-       memset(skb->data, 0, sizeof(struct rtl8xxxu_rx_desc));
+       memset(skb->data, 0, rx_desc_sz);
        usb_fill_bulk_urb(&rx_urb->urb, priv->udev, priv->pipe_in, skb->data,
                          skb_size, rtl8xxxu_rx_complete, skb);
        usb_anchor_urb(&rx_urb->urb, &priv->rx_anchor);
@@ -8154,6 +9597,8 @@ static void rtl8xxxu_stop(struct ieee80211_hw *hw)
        if (priv->usb_interrupts)
                usb_kill_anchored_urbs(&priv->int_anchor);
 
+       rtl8xxxu_write8(priv, REG_TXPAUSE, 0xff);
+
        priv->fops->disable_rf(priv);
 
        /*
@@ -8286,6 +9731,10 @@ static int rtl8xxxu_probe(struct usb_interface *interface,
                if (id->idProduct == 0x7811)
                        untested = 0;
                break;
+       case 0x050d:
+               if (id->idProduct == 0x1004)
+                       untested = 0;
+               break;
        default:
                break;
        }
@@ -8414,13 +9863,14 @@ static void rtl8xxxu_disconnect(struct usb_interface *interface)
        hw = usb_get_intfdata(interface);
        priv = hw->priv;
 
-       rtl8xxxu_disable_device(hw);
+       ieee80211_unregister_hw(hw);
+
+       priv->fops->power_off(priv);
+
        usb_set_intfdata(interface, NULL);
 
        dev_info(&priv->udev->dev, "disconnecting\n");
 
-       ieee80211_unregister_hw(hw);
-
        kfree(priv->fw_data);
        mutex_destroy(&priv->usb_buf_mutex);
        mutex_destroy(&priv->h2c_mutex);
@@ -8436,22 +9886,30 @@ static struct rtl8xxxu_fileops rtl8723au_fops = {
        .power_off = rtl8xxxu_power_off,
        .reset_8051 = rtl8xxxu_reset_8051,
        .llt_init = rtl8xxxu_init_llt_table,
-       .phy_iq_calibrate = rtl8723au_phy_iq_calibrate,
-       .config_channel = rtl8723au_config_channel,
-       .parse_rx_desc = rtl8723au_parse_rx_desc,
-       .enable_rf = rtl8723a_enable_rf,
-       .disable_rf = rtl8723a_disable_rf,
-       .set_tx_power = rtl8723a_set_tx_power,
-       .update_rate_mask = rtl8723au_update_rate_mask,
-       .report_connect = rtl8723au_report_connect,
+       .init_phy_bb = rtl8xxxu_gen1_init_phy_bb,
+       .init_phy_rf = rtl8723au_init_phy_rf,
+       .phy_iq_calibrate = rtl8xxxu_gen1_phy_iq_calibrate,
+       .config_channel = rtl8xxxu_gen1_config_channel,
+       .parse_rx_desc = rtl8xxxu_parse_rxdesc16,
+       .enable_rf = rtl8xxxu_gen1_enable_rf,
+       .disable_rf = rtl8xxxu_gen1_disable_rf,
+       .usb_quirks = rtl8xxxu_gen1_usb_quirks,
+       .set_tx_power = rtl8xxxu_gen1_set_tx_power,
+       .update_rate_mask = rtl8xxxu_update_rate_mask,
+       .report_connect = rtl8xxxu_gen1_report_connect,
        .writeN_block_size = 1024,
        .mbox_ext_reg = REG_HMBOX_EXT_0,
        .mbox_ext_width = 2,
        .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
+       .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
        .adda_1t_init = 0x0b1b25a0,
        .adda_1t_path_on = 0x0bdb25a0,
        .adda_2t_path_on_a = 0x04db25a4,
        .adda_2t_path_on_b = 0x0b1b25a4,
+       .trxff_boundary = 0x27ff,
+       .pbp_rx = PBP_PAGE_SIZE_128,
+       .pbp_tx = PBP_PAGE_SIZE_128,
+       .mactable = rtl8xxxu_gen1_mac_init_table,
 };
 
 static struct rtl8xxxu_fileops rtl8723bu_fops = {
@@ -8461,26 +9919,34 @@ static struct rtl8xxxu_fileops rtl8723bu_fops = {
        .power_off = rtl8723bu_power_off,
        .reset_8051 = rtl8723bu_reset_8051,
        .llt_init = rtl8xxxu_auto_llt_table,
+       .init_phy_bb = rtl8723bu_init_phy_bb,
+       .init_phy_rf = rtl8723bu_init_phy_rf,
        .phy_init_antenna_selection = rtl8723bu_phy_init_antenna_selection,
        .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate,
-       .config_channel = rtl8723bu_config_channel,
-       .parse_rx_desc = rtl8723bu_parse_rx_desc,
+       .config_channel = rtl8xxxu_gen2_config_channel,
+       .parse_rx_desc = rtl8xxxu_parse_rxdesc24,
        .init_aggregation = rtl8723bu_init_aggregation,
        .init_statistics = rtl8723bu_init_statistics,
        .enable_rf = rtl8723b_enable_rf,
-       .disable_rf = rtl8723b_disable_rf,
+       .disable_rf = rtl8xxxu_gen2_disable_rf,
+       .usb_quirks = rtl8xxxu_gen2_usb_quirks,
        .set_tx_power = rtl8723b_set_tx_power,
-       .update_rate_mask = rtl8723bu_update_rate_mask,
-       .report_connect = rtl8723bu_report_connect,
+       .update_rate_mask = rtl8xxxu_gen2_update_rate_mask,
+       .report_connect = rtl8xxxu_gen2_report_connect,
        .writeN_block_size = 1024,
        .mbox_ext_reg = REG_HMBOX_EXT0_8723B,
        .mbox_ext_width = 4,
        .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40),
+       .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24),
        .has_s0s1 = 1,
        .adda_1t_init = 0x01c00014,
        .adda_1t_path_on = 0x01c00014,
        .adda_2t_path_on_a = 0x01c00014,
        .adda_2t_path_on_b = 0x01c00014,
+       .trxff_boundary = 0x3f7f,
+       .pbp_rx = PBP_PAGE_SIZE_256,
+       .pbp_tx = PBP_PAGE_SIZE_256,
+       .mactable = rtl8723b_mac_init_table,
 };
 
 #ifdef CONFIG_RTL8XXXU_UNTESTED
@@ -8492,22 +9958,30 @@ static struct rtl8xxxu_fileops rtl8192cu_fops = {
        .power_off = rtl8xxxu_power_off,
        .reset_8051 = rtl8xxxu_reset_8051,
        .llt_init = rtl8xxxu_init_llt_table,
-       .phy_iq_calibrate = rtl8723au_phy_iq_calibrate,
-       .config_channel = rtl8723au_config_channel,
-       .parse_rx_desc = rtl8723au_parse_rx_desc,
-       .enable_rf = rtl8723a_enable_rf,
-       .disable_rf = rtl8723a_disable_rf,
-       .set_tx_power = rtl8723a_set_tx_power,
-       .update_rate_mask = rtl8723au_update_rate_mask,
-       .report_connect = rtl8723au_report_connect,
+       .init_phy_bb = rtl8xxxu_gen1_init_phy_bb,
+       .init_phy_rf = rtl8192cu_init_phy_rf,
+       .phy_iq_calibrate = rtl8xxxu_gen1_phy_iq_calibrate,
+       .config_channel = rtl8xxxu_gen1_config_channel,
+       .parse_rx_desc = rtl8xxxu_parse_rxdesc16,
+       .enable_rf = rtl8xxxu_gen1_enable_rf,
+       .disable_rf = rtl8xxxu_gen1_disable_rf,
+       .usb_quirks = rtl8xxxu_gen1_usb_quirks,
+       .set_tx_power = rtl8xxxu_gen1_set_tx_power,
+       .update_rate_mask = rtl8xxxu_update_rate_mask,
+       .report_connect = rtl8xxxu_gen1_report_connect,
        .writeN_block_size = 128,
        .mbox_ext_reg = REG_HMBOX_EXT_0,
        .mbox_ext_width = 2,
        .tx_desc_size = sizeof(struct rtl8xxxu_txdesc32),
+       .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc16),
        .adda_1t_init = 0x0b1b25a0,
        .adda_1t_path_on = 0x0bdb25a0,
        .adda_2t_path_on_a = 0x04db25a4,
        .adda_2t_path_on_b = 0x0b1b25a4,
+       .trxff_boundary = 0x27ff,
+       .pbp_rx = PBP_PAGE_SIZE_128,
+       .pbp_tx = PBP_PAGE_SIZE_128,
+       .mactable = rtl8xxxu_gen1_mac_init_table,
 };
 
 #endif
@@ -8519,23 +9993,33 @@ static struct rtl8xxxu_fileops rtl8192eu_fops = {
        .power_off = rtl8xxxu_power_off,
        .reset_8051 = rtl8xxxu_reset_8051,
        .llt_init = rtl8xxxu_auto_llt_table,
-       .phy_iq_calibrate = rtl8723bu_phy_iq_calibrate,
-       .config_channel = rtl8723bu_config_channel,
-       .parse_rx_desc = rtl8723bu_parse_rx_desc,
-       .enable_rf = rtl8723b_enable_rf,
-       .disable_rf = rtl8723b_disable_rf,
-       .set_tx_power = rtl8723b_set_tx_power,
-       .update_rate_mask = rtl8723bu_update_rate_mask,
-       .report_connect = rtl8723bu_report_connect,
+       .init_phy_bb = rtl8192eu_init_phy_bb,
+       .init_phy_rf = rtl8192eu_init_phy_rf,
+       .phy_iq_calibrate = rtl8192eu_phy_iq_calibrate,
+       .config_channel = rtl8xxxu_gen2_config_channel,
+       .parse_rx_desc = rtl8xxxu_parse_rxdesc24,
+       .enable_rf = rtl8192e_enable_rf,
+       .disable_rf = rtl8xxxu_gen2_disable_rf,
+       .usb_quirks = rtl8xxxu_gen2_usb_quirks,
+       .set_tx_power = rtl8192e_set_tx_power,
+       .update_rate_mask = rtl8xxxu_gen2_update_rate_mask,
+       .report_connect = rtl8xxxu_gen2_report_connect,
        .writeN_block_size = 128,
        .mbox_ext_reg = REG_HMBOX_EXT0_8723B,
        .mbox_ext_width = 4,
        .tx_desc_size = sizeof(struct rtl8xxxu_txdesc40),
-       .has_s0s1 = 1,
+       .rx_desc_size = sizeof(struct rtl8xxxu_rxdesc24),
+       .has_s0s1 = 0,
        .adda_1t_init = 0x0fc01616,
        .adda_1t_path_on = 0x0fc01616,
        .adda_2t_path_on_a = 0x0fc01616,
        .adda_2t_path_on_b = 0x0fc01616,
+       .trxff_boundary = 0x3cff,
+       .mactable = rtl8192e_mac_init_table,
+       .total_page_num = TX_TOTAL_PAGE_NUM_8192E,
+       .page_num_hi = TX_PAGE_NUM_HI_PQ_8192E,
+       .page_num_lo = TX_PAGE_NUM_LO_PQ_8192E,
+       .page_num_norm = TX_PAGE_NUM_NORM_PQ_8192E,
 };
 
 static struct usb_device_id dev_table[] = {
@@ -8560,6 +10044,9 @@ static struct usb_device_id dev_table[] = {
 /* Tested by Larry Finger */
 {USB_DEVICE_AND_INTERFACE_INFO(0x7392, 0x7811, 0xff, 0xff, 0xff),
        .driver_info = (unsigned long)&rtl8192cu_fops},
+/* Tested by Andrea Merello */
+{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1004, 0xff, 0xff, 0xff),
+       .driver_info = (unsigned long)&rtl8192cu_fops},
 /* Currently untested 8188 series devices */
 {USB_DEVICE_AND_INTERFACE_INFO(USB_VENDOR_ID_REALTEK, 0x8191, 0xff, 0xff, 0xff),
        .driver_info = (unsigned long)&rtl8192cu_fops},
@@ -8644,8 +10131,6 @@ static struct usb_device_id dev_table[] = {
 /* Currently untested 8192 series devices */
 {USB_DEVICE_AND_INTERFACE_INFO(0x04bb, 0x0950, 0xff, 0xff, 0xff),
        .driver_info = (unsigned long)&rtl8192cu_fops},
-{USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x1004, 0xff, 0xff, 0xff),
-       .driver_info = (unsigned long)&rtl8192cu_fops},
 {USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2102, 0xff, 0xff, 0xff),
        .driver_info = (unsigned long)&rtl8192cu_fops},
 {USB_DEVICE_AND_INTERFACE_INFO(0x050d, 0x2103, 0xff, 0xff, 0xff),
@@ -8701,6 +10186,7 @@ static struct usb_driver rtl8xxxu_driver = {
        .probe = rtl8xxxu_probe,
        .disconnect = rtl8xxxu_disconnect,
        .id_table = dev_table,
+       .no_dynamic_id = 1,
        .disable_hub_initiated_lpm = 1,
 };
 
index 455e112..3e2643c 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ * Copyright (c) 2014 - 2016 Jes Sorensen <Jes.Sorensen@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
 #define REALTEK_USB_CMD_IDX            0x00
 
 #define TX_TOTAL_PAGE_NUM              0xf8
+#define TX_TOTAL_PAGE_NUM_8192E                0xf3
 /* (HPQ + LPQ + NPQ + PUBQ) = TX_TOTAL_PAGE_NUM */
 #define TX_PAGE_NUM_PUBQ               0xe7
 #define TX_PAGE_NUM_HI_PQ              0x0c
 #define TX_PAGE_NUM_LO_PQ              0x02
 #define TX_PAGE_NUM_NORM_PQ            0x02
 
+#define TX_PAGE_NUM_PUBQ_8192E         0xe7
+#define TX_PAGE_NUM_HI_PQ_8192E                0x08
+#define TX_PAGE_NUM_LO_PQ_8192E                0x0c
+#define TX_PAGE_NUM_NORM_PQ_8192E      0x00
+
 #define RTL_FW_PAGE_SIZE               4096
 #define RTL8XXXU_FIRMWARE_POLL_MAX     1000
 
@@ -95,7 +101,7 @@ enum rtl8xxxu_rx_type {
        RX_TYPE_ERROR = -1
 };
 
-struct rtl8xxxu_rx_desc {
+struct rtl8xxxu_rxdesc16 {
 #ifdef __LITTLE_ENDIAN
        u32 pktlen:14;
        u32 crc32:1;
@@ -231,7 +237,7 @@ struct rtl8xxxu_rx_desc {
 #endif
 };
 
-struct rtl8723bu_rx_desc {
+struct rtl8xxxu_rxdesc24 {
 #ifdef __LITTLE_ENDIAN
        u32 pktlen:14;
        u32 crc32:1;
@@ -623,6 +629,31 @@ struct rtl8xxxu_firmware_header {
        u8      data[0];
 };
 
+/*
+ * 8723au/8192cu/8188ru required base power index offset tables.
+ */
+struct rtl8xxxu_power_base {
+       u32 reg_0e00;
+       u32 reg_0e04;
+       u32 reg_0e08;
+       u32 reg_086c;
+
+       u32 reg_0e10;
+       u32 reg_0e14;
+       u32 reg_0e18;
+       u32 reg_0e1c;
+
+       u32 reg_0830;
+       u32 reg_0834;
+       u32 reg_0838;
+       u32 reg_086c_2;
+
+       u32 reg_083c;
+       u32 reg_0848;
+       u32 reg_084c;
+       u32 reg_0868;
+};
+
 /*
  * The 8723au has 3 channel groups: 1-3, 4-9, and 10-14
  */
@@ -787,55 +818,49 @@ struct rtl8192eu_efuse_tx_power {
        u8 cck_base[6];
        u8 ht40_base[5];
        struct rtl8723au_idx ht20_ofdm_1s_diff;
-       struct rtl8723au_idx ht40_ht20_2s_diff;
-       struct rtl8723au_idx ofdm_cck_2s_diff; /* not used */
-       struct rtl8723au_idx ht40_ht20_3s_diff;
-       struct rtl8723au_idx ofdm_cck_3s_diff; /* not used */
-       struct rtl8723au_idx ht40_ht20_4s_diff;
-       struct rtl8723au_idx ofdm_cck_4s_diff; /* not used */
+       struct rtl8723bu_pwr_idx pwr_diff[3];
+       u8 dummy5g[24]; /* max channel group (14) + power diff offset (10) */
 };
 
 struct rtl8192eu_efuse {
        __le16 rtl_id;
        u8 res0[0x0e];
        struct rtl8192eu_efuse_tx_power tx_power_index_A;       /* 0x10 */
-       struct rtl8192eu_efuse_tx_power tx_power_index_B;       /* 0x22 */
-       struct rtl8192eu_efuse_tx_power tx_power_index_C;       /* 0x34 */
-       struct rtl8192eu_efuse_tx_power tx_power_index_D;       /* 0x46 */
-       u8 res1[0x60];
+       struct rtl8192eu_efuse_tx_power tx_power_index_B;       /* 0x3a */
+       u8 res2[0x54];
        u8 channel_plan;                /* 0xb8 */
        u8 xtal_k;
        u8 thermal_meter;
        u8 iqk_lck;
        u8 pa_type;                     /* 0xbc */
        u8 lna_type_2g;                 /* 0xbd */
-       u8 res2[1];
+       u8 res3[1];
        u8 lna_type_5g;                 /* 0xbf */
-       u8 res13[1];
+       u8 res4[1];
        u8 rf_board_option;
        u8 rf_feature_option;
        u8 rf_bt_setting;
        u8 eeprom_version;
        u8 eeprom_customer_id;
-       u8 res3[3];
+       u8 res5[3];
        u8 rf_antenna_option;           /* 0xc9 */
-       u8 res4[6];
+       u8 res6[6];
        u8 vid;                         /* 0xd0 */
-       u8 res5[1];
+       u8 res7[1];
        u8 pid;                         /* 0xd2 */
-       u8 res6[1];
+       u8 res8[1];
        u8 usb_optional_function;
-       u8 res7[2];
+       u8 res9[2];
        u8 mac_addr[ETH_ALEN];          /* 0xd7 */
-       u8 res8[2];
+       u8 res10[2];
        u8 vendor_name[7];
-       u8 res9[2];
+       u8 res11[2];
        u8 device_name[0x0b];           /* 0xe8 */
-       u8 res10[2];
+       u8 res12[2];
        u8 serial[0x0b];                /* 0xf5 */
-       u8 res11[0x30];
+       u8 res13[0x30];
        u8 unknown[0x0d];               /* 0x130 */
-       u8 res12[0xc3];
+       u8 res14[0xc3];
 };
 
 struct rtl8xxxu_reg8val {
@@ -1201,6 +1226,7 @@ struct rtl8xxxu_priv {
        struct rtl8723au_idx ofdm_tx_power_diff[RTL8723B_TX_COUNT];
        struct rtl8723au_idx ht20_tx_power_diff[RTL8723B_TX_COUNT];
        struct rtl8723au_idx ht40_tx_power_diff[RTL8723B_TX_COUNT];
+       struct rtl8xxxu_power_base *power_base;
        u32 chip_cut:4;
        u32 rom_rev:4;
        u32 is_multi_func:1;
@@ -1228,7 +1254,6 @@ struct rtl8xxxu_priv {
        u8 rf_paths;
        u8 rx_paths;
        u8 tx_paths;
-       u32 rf_mode_ag[2];
        u32 rege94;
        u32 rege9c;
        u32 regeb4;
@@ -1262,6 +1287,7 @@ struct rtl8xxxu_priv {
        u32 bb_recovery_backup[RTL8XXXU_BB_REGS];
        enum rtl8xxxu_rtl_chip rtl_chip;
        u8 pi_enabled:1;
+       u8 no_pape:1;
        u8 int_buf[USB_INTR_CONTENT_LENGTH];
 };
 
@@ -1284,6 +1310,8 @@ struct rtl8xxxu_fileops {
        void (*power_off) (struct rtl8xxxu_priv *priv);
        void (*reset_8051) (struct rtl8xxxu_priv *priv);
        int (*llt_init) (struct rtl8xxxu_priv *priv, u8 last_tx_page);
+       void (*init_phy_bb) (struct rtl8xxxu_priv *priv);
+       int (*init_phy_rf) (struct rtl8xxxu_priv *priv);
        void (*phy_init_antenna_selection) (struct rtl8xxxu_priv *priv);
        void (*phy_iq_calibrate) (struct rtl8xxxu_priv *priv);
        void (*config_channel) (struct ieee80211_hw *hw);
@@ -1293,6 +1321,7 @@ struct rtl8xxxu_fileops {
        void (*init_statistics) (struct rtl8xxxu_priv *priv);
        void (*enable_rf) (struct rtl8xxxu_priv *priv);
        void (*disable_rf) (struct rtl8xxxu_priv *priv);
+       void (*usb_quirks) (struct rtl8xxxu_priv *priv);
        void (*set_tx_power) (struct rtl8xxxu_priv *priv, int channel,
                              bool ht40);
        void (*update_rate_mask) (struct rtl8xxxu_priv *priv,
@@ -1303,9 +1332,18 @@ struct rtl8xxxu_fileops {
        u16 mbox_ext_reg;
        char mbox_ext_width;
        char tx_desc_size;
+       char rx_desc_size;
        char has_s0s1;
        u32 adda_1t_init;
        u32 adda_1t_path_on;
        u32 adda_2t_path_on_a;
        u32 adda_2t_path_on_b;
+       u16 trxff_boundary;
+       u8 pbp_rx;
+       u8 pbp_tx;
+       struct rtl8xxxu_reg8val *mactable;
+       u8 total_page_num;
+       u8 page_num_hi;
+       u8 page_num_lo;
+       u8 page_num_norm;
 };
index ade42fe..b0e0c64 100644 (file)
@@ -1,5 +1,5 @@
 /*
- * Copyright (c) 2014 - 2015 Jes Sorensen <Jes.Sorensen@redhat.com>
+ * Copyright (c) 2014 - 2016 Jes Sorensen <Jes.Sorensen@redhat.com>
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
 #define  AFE_XTAL_GATE_DIG             BIT(17)
 #define  AFE_XTAL_BT_GATE              BIT(20)
 
+/*
+ * 0x0028 is also known as REG_AFE_CTRL2 on 8723bu/8192eu
+ */
 #define REG_AFE_PLL_CTRL               0x0028
 #define  AFE_PLL_ENABLE                        BIT(0)
 #define  AFE_PLL_320_ENABLE            BIT(1)
                                                   control */
 #define  MULTI_GPS_FUNC_EN             BIT(22) /* GPS function enable */
 
+#define REG_AFE_CTRL4                  0x0078  /* 8192eu/8723bu */
 #define REG_LDO_SW_CTRL                        0x007c  /* 8192eu */
 
 #define REG_MCU_FW_DL                  0x0080
 #define REG_RQPN                       0x0200
 #define  RQPN_HI_PQ_SHIFT              0
 #define  RQPN_LO_PQ_SHIFT              8
-#define  RQPN_NORM_PQ_SHIFT            16
+#define  RQPN_PUB_PQ_SHIFT             16
 #define  RQPN_LOAD                     BIT(31)
 
 #define REG_FIFOPAGE                   0x0204
 #define REG_PKT_VO_VI_LIFE_TIME                0x04c0
 #define REG_PKT_BE_BK_LIFE_TIME                0x04c2
 #define REG_STBC_SETTING               0x04c4
+#define REG_QUEUE_CTRL                 0x04c6
 #define REG_HT_SINGLE_AMPDU_8723B      0x04c7
 #define REG_PROT_MODE_CTRL             0x04c8
 #define REG_MAX_AGGR_NUM               0x04ca
 #define  CCK0_SIDEBAND                 BIT(4)
 
 #define REG_CCK0_AFE_SETTING           0x0a04
+#define  CCK0_AFE_RX_MASK              0x0f000000
+#define  CCK0_AFE_RX_ANT_AB            BIT(24)
+#define  CCK0_AFE_RX_ANT_A             0
+#define  CCK0_AFE_RX_ANT_B             (BIT(24) | BIT(26))
 
 #define REG_CONFIG_ANT_A               0x0b68
 #define REG_CONFIG_ANT_B               0x0b6c
 #define  USB_HIMR_ROK                  BIT(0)  /*  Receive DMA OK Interrupt */
 
 #define REG_USB_SPECIAL_OPTION         0xfe55
+#define REG_USB_HRPWM                  0xfe58
 #define REG_USB_DMA_AGG_TO             0xfe5b
 #define REG_USB_AGG_TO                 0xfe5c
 #define REG_USB_AGG_TH                 0xfe5d
 #define RF6052_REG_T_METER_8723B       0x42
 #define RF6052_REG_UNKNOWN_43          0x43
 #define RF6052_REG_UNKNOWN_55          0x55
+#define RF6052_REG_UNKNOWN_56          0x56
 #define RF6052_REG_S0S1                        0xb0
 #define RF6052_REG_UNKNOWN_DF          0xdf
 #define RF6052_REG_UNKNOWN_ED          0xed
index ddf74d5..0c3b9ce 100644 (file)
@@ -959,7 +959,7 @@ static void _rtl8821ae_phy_store_txpower_by_rate_base(struct ieee80211_hw *hw)
 static void _phy_convert_txpower_dbm_to_relative_value(u32 *data, u8 start,
                                                u8 end, u8 base_val)
 {
-       char i = 0;
+       int i;
        u8 temp_value = 0;
        u32 temp_data = 0;