Merge branch 'master' of git://git.kernel.org/pub/scm/linux/kernel/git/linville/wirel...
authorJohn W. Linville <linville@tuxdriver.com>
Wed, 28 Nov 2012 15:56:03 +0000 (10:56 -0500)
committerJohn W. Linville <linville@tuxdriver.com>
Wed, 28 Nov 2012 15:56:03 +0000 (10:56 -0500)
Conflicts:
drivers/net/wireless/iwlwifi/pcie/tx.c

289 files changed:
MAINTAINERS
drivers/bluetooth/btusb.c
drivers/net/wireless/at76c50x-usb.c
drivers/net/wireless/ath/ar5523/ar5523.c
drivers/net/wireless/ath/ar5523/ar5523_hw.h
drivers/net/wireless/ath/ath5k/ahb.c
drivers/net/wireless/ath/ath5k/base.c
drivers/net/wireless/ath/ath5k/mac80211-ops.c
drivers/net/wireless/ath/ath5k/reset.c
drivers/net/wireless/ath/ath6kl/Kconfig
drivers/net/wireless/ath/ath6kl/Makefile
drivers/net/wireless/ath/ath6kl/cfg80211.c
drivers/net/wireless/ath/ath6kl/cfg80211.h
drivers/net/wireless/ath/ath6kl/core.c
drivers/net/wireless/ath/ath6kl/core.h
drivers/net/wireless/ath/ath6kl/debug.h
drivers/net/wireless/ath/ath6kl/hif.c
drivers/net/wireless/ath/ath6kl/htc_mbox.c
drivers/net/wireless/ath/ath6kl/htc_pipe.c
drivers/net/wireless/ath/ath6kl/init.c
drivers/net/wireless/ath/ath6kl/main.c
drivers/net/wireless/ath/ath6kl/recovery.c [new file with mode: 0644]
drivers/net/wireless/ath/ath6kl/sdio.c
drivers/net/wireless/ath/ath6kl/txrx.c
drivers/net/wireless/ath/ath6kl/usb.c
drivers/net/wireless/ath/ath6kl/wmi.c
drivers/net/wireless/ath/ath6kl/wmi.h
drivers/net/wireless/ath/ath9k/ar9003_calib.c
drivers/net/wireless/ath/ath9k/ar9003_hw.c
drivers/net/wireless/ath/ath9k/ar9003_mci.c
drivers/net/wireless/ath/ath9k/ar9003_phy.c
drivers/net/wireless/ath/ath9k/ar9003_phy.h
drivers/net/wireless/ath/ath9k/ar9462_2p0_initvals.h
drivers/net/wireless/ath/ath9k/ar9485_initvals.h
drivers/net/wireless/ath/ath9k/ath9k.h
drivers/net/wireless/ath/ath9k/beacon.c
drivers/net/wireless/ath/ath9k/btcoex.c
drivers/net/wireless/ath/ath9k/btcoex.h
drivers/net/wireless/ath/ath9k/common.h
drivers/net/wireless/ath/ath9k/debug.c
drivers/net/wireless/ath/ath9k/debug.h
drivers/net/wireless/ath/ath9k/dfs_pattern_detector.c
drivers/net/wireless/ath/ath9k/dfs_pattern_detector.h
drivers/net/wireless/ath/ath9k/gpio.c
drivers/net/wireless/ath/ath9k/htc.h
drivers/net/wireless/ath/ath9k/htc_drv_beacon.c
drivers/net/wireless/ath/ath9k/htc_drv_debug.c
drivers/net/wireless/ath/ath9k/htc_drv_gpio.c
drivers/net/wireless/ath/ath9k/htc_drv_init.c
drivers/net/wireless/ath/ath9k/htc_drv_main.c
drivers/net/wireless/ath/ath9k/htc_drv_txrx.c
drivers/net/wireless/ath/ath9k/hw.c
drivers/net/wireless/ath/ath9k/hw.h
drivers/net/wireless/ath/ath9k/init.c
drivers/net/wireless/ath/ath9k/link.c
drivers/net/wireless/ath/ath9k/main.c
drivers/net/wireless/ath/ath9k/mci.c
drivers/net/wireless/ath/ath9k/pci.c
drivers/net/wireless/ath/ath9k/rc.c
drivers/net/wireless/ath/ath9k/rc.h
drivers/net/wireless/ath/ath9k/recv.c
drivers/net/wireless/ath/ath9k/xmit.c
drivers/net/wireless/ath/carl9170/fw.c
drivers/net/wireless/b43/xmit.c
drivers/net/wireless/b43legacy/xmit.c
drivers/net/wireless/brcm80211/Kconfig
drivers/net/wireless/brcm80211/brcmfmac/Makefile
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh.c
drivers/net/wireless/brcm80211/brcmfmac/bcmsdh_sdmmc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_bus.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_cdc.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_common.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_dbg.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_linux.c
drivers/net/wireless/brcm80211/brcmfmac/dhd_proto.h
drivers/net/wireless/brcm80211/brcmfmac/dhd_sdio.c
drivers/net/wireless/brcm80211/brcmfmac/fweh.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/fweh.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmfmac/fwil.c
drivers/net/wireless/brcm80211/brcmfmac/usb.c
drivers/net/wireless/brcm80211/brcmfmac/usb.h
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.c
drivers/net/wireless/brcm80211/brcmfmac/wl_cfg80211.h
drivers/net/wireless/brcm80211/brcmsmac/Makefile
drivers/net/wireless/brcm80211/brcmsmac/ampdu.c
drivers/net/wireless/brcm80211/brcmsmac/ampdu.h
drivers/net/wireless/brcm80211/brcmsmac/antsel.c
drivers/net/wireless/brcm80211/brcmsmac/brcms_trace_events.h
drivers/net/wireless/brcm80211/brcmsmac/channel.c
drivers/net/wireless/brcm80211/brcmsmac/debug.c [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmsmac/debug.h [new file with mode: 0644]
drivers/net/wireless/brcm80211/brcmsmac/dma.c
drivers/net/wireless/brcm80211/brcmsmac/dma.h
drivers/net/wireless/brcm80211/brcmsmac/mac80211_if.c
drivers/net/wireless/brcm80211/brcmsmac/main.c
drivers/net/wireless/brcm80211/brcmsmac/main.h
drivers/net/wireless/brcm80211/brcmsmac/pub.h
drivers/net/wireless/brcm80211/brcmsmac/stf.c
drivers/net/wireless/brcm80211/brcmsmac/types.h
drivers/net/wireless/brcm80211/include/defs.h
drivers/net/wireless/ipw2x00/ipw2100.c
drivers/net/wireless/ipw2x00/ipw2200.c
drivers/net/wireless/ipw2x00/libipw.h
drivers/net/wireless/ipw2x00/libipw_geo.c
drivers/net/wireless/iwlegacy/3945.c
drivers/net/wireless/iwlegacy/4965-mac.c
drivers/net/wireless/iwlegacy/common.h
drivers/net/wireless/iwlwifi/Kconfig
drivers/net/wireless/iwlwifi/dvm/agn.h
drivers/net/wireless/iwlwifi/dvm/commands.h
drivers/net/wireless/iwlwifi/dvm/debugfs.c
drivers/net/wireless/iwlwifi/dvm/dev.h
drivers/net/wireless/iwlwifi/dvm/lib.c
drivers/net/wireless/iwlwifi/dvm/mac80211.c
drivers/net/wireless/iwlwifi/dvm/main.c
drivers/net/wireless/iwlwifi/dvm/rx.c
drivers/net/wireless/iwlwifi/dvm/tx.c
drivers/net/wireless/iwlwifi/dvm/ucode.c
drivers/net/wireless/iwlwifi/iwl-config.h
drivers/net/wireless/iwlwifi/iwl-devtrace.h
drivers/net/wireless/iwlwifi/iwl-eeprom-parse.c
drivers/net/wireless/iwlwifi/iwl-fh.h
drivers/net/wireless/iwlwifi/iwl-trans.h
drivers/net/wireless/iwlwifi/pcie/drv.c
drivers/net/wireless/iwlwifi/pcie/internal.h
drivers/net/wireless/iwlwifi/pcie/rx.c
drivers/net/wireless/iwlwifi/pcie/trans.c
drivers/net/wireless/iwlwifi/pcie/tx.c
drivers/net/wireless/libertas/cfg.c
drivers/net/wireless/libertas/if_sdio.c
drivers/net/wireless/mac80211_hwsim.c
drivers/net/wireless/mwifiex/11n_aggr.c
drivers/net/wireless/mwifiex/Kconfig
drivers/net/wireless/mwifiex/cfg80211.c
drivers/net/wireless/mwifiex/cmdevt.c
drivers/net/wireless/mwifiex/debugfs.c
drivers/net/wireless/mwifiex/init.c
drivers/net/wireless/mwifiex/join.c
drivers/net/wireless/mwifiex/main.c
drivers/net/wireless/mwifiex/main.h
drivers/net/wireless/mwifiex/sdio.c
drivers/net/wireless/mwifiex/sdio.h
drivers/net/wireless/mwifiex/sta_event.c
drivers/net/wireless/mwifiex/sta_ioctl.c
drivers/net/wireless/mwifiex/txrx.c
drivers/net/wireless/mwifiex/uap_event.c
drivers/net/wireless/mwifiex/usb.c
drivers/net/wireless/mwifiex/wmm.c
drivers/net/wireless/mwifiex/wmm.h
drivers/net/wireless/mwl8k.c
drivers/net/wireless/orinoco/cfg.c
drivers/net/wireless/p54/txrx.c
drivers/net/wireless/rndis_wlan.c
drivers/net/wireless/rt2x00/rt2800usb.c
drivers/net/wireless/rt2x00/rt2x00dev.c
drivers/net/wireless/rt2x00/rt2x00mac.c
drivers/net/wireless/rtl818x/rtl8180/dev.c
drivers/net/wireless/rtl818x/rtl8187/dev.c
drivers/net/wireless/rtlwifi/Kconfig
drivers/net/wireless/rtlwifi/Makefile
drivers/net/wireless/rtlwifi/base.c
drivers/net/wireless/rtlwifi/base.h
drivers/net/wireless/rtlwifi/cam.c
drivers/net/wireless/rtlwifi/core.c
drivers/net/wireless/rtlwifi/debug.h
drivers/net/wireless/rtlwifi/pci.c
drivers/net/wireless/rtlwifi/pci.h
drivers/net/wireless/rtlwifi/rc.c
drivers/net/wireless/rtlwifi/rtl8192ce/trx.c
drivers/net/wireless/rtlwifi/rtl8192cu/trx.c
drivers/net/wireless/rtlwifi/rtl8192de/trx.c
drivers/net/wireless/rtlwifi/rtl8192se/trx.c
drivers/net/wireless/rtlwifi/rtl8723ae/Makefile [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/btc.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/def.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/dm.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/dm.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/fw.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/fw.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/hw.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/hw.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/led.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/led.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/phy.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/phy.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/reg.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/rf.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/rf.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/sw.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/sw.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/table.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/table.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/trx.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/rtl8723ae/trx.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/stats.c [new file with mode: 0644]
drivers/net/wireless/rtlwifi/stats.h [new file with mode: 0644]
drivers/net/wireless/rtlwifi/wifi.h
drivers/net/wireless/ti/wl1251/rx.c
drivers/net/wireless/ti/wlcore/main.c
drivers/nfc/pn544/i2c.c
include/linux/bcma/bcma.h
include/linux/ieee80211.h
include/linux/nfc/pn544.h [deleted file]
include/linux/platform_data/pn544.h [new file with mode: 0644]
include/linux/ssb/ssb_regs.h
include/net/bluetooth/amp.h
include/net/bluetooth/hci.h
include/net/bluetooth/hci_core.h
include/net/bluetooth/l2cap.h
include/net/cfg80211.h
include/net/mac80211.h
include/net/nfc/hci.h
include/uapi/linux/nl80211.h
net/bluetooth/Kconfig
net/bluetooth/a2mp.c
net/bluetooth/amp.c
net/bluetooth/bnep/netdev.c
net/bluetooth/cmtp/capi.c
net/bluetooth/cmtp/sock.c
net/bluetooth/hci_conn.c
net/bluetooth/hci_core.c
net/bluetooth/hci_event.c
net/bluetooth/l2cap_core.c
net/bluetooth/l2cap_sock.c
net/bluetooth/mgmt.c
net/mac80211/aes_cmac.c
net/mac80211/agg-rx.c
net/mac80211/agg-tx.c
net/mac80211/cfg.c
net/mac80211/chan.c
net/mac80211/debugfs_key.c
net/mac80211/debugfs_netdev.c
net/mac80211/debugfs_sta.c
net/mac80211/driver-ops.h
net/mac80211/ht.c
net/mac80211/ibss.c
net/mac80211/ieee80211_i.h
net/mac80211/iface.c
net/mac80211/key.c
net/mac80211/key.h
net/mac80211/main.c
net/mac80211/mesh.c
net/mac80211/mesh.h
net/mac80211/mesh_plink.c
net/mac80211/mesh_sync.c
net/mac80211/mlme.c
net/mac80211/offchannel.c
net/mac80211/pm.c
net/mac80211/rate.c
net/mac80211/rate.h
net/mac80211/rx.c
net/mac80211/scan.c
net/mac80211/sta_info.c
net/mac80211/sta_info.h
net/mac80211/status.c
net/mac80211/trace.h
net/mac80211/tx.c
net/mac80211/util.c
net/mac80211/wme.c
net/nfc/hci/command.c
net/nfc/hci/core.c
net/nfc/llcp/commands.c
net/nfc/llcp/llcp.c
net/wireless/Kconfig
net/wireless/ap.c
net/wireless/chan.c
net/wireless/core.c
net/wireless/core.h
net/wireless/ibss.c
net/wireless/mesh.c
net/wireless/mlme.c
net/wireless/nl80211.c
net/wireless/nl80211.h
net/wireless/rdev-ops.h
net/wireless/scan.c
net/wireless/trace.h
net/wireless/util.c
net/wireless/wext-compat.c
net/wireless/wext-sme.c

index 9087e0d6f1a7bdcb31cdb4144c39095eb72987cb..5d72dd57b78a27dc38d3bfd50f814978bf741f02 100644 (file)
@@ -5157,6 +5157,7 @@ F:        net/nfc/
 F:     include/linux/nfc.h
 F:     include/net/nfc/
 F:     drivers/nfc/
+F:     include/linux/platform_data/pn544.h
 
 NFS, SUNRPC, AND LOCKD CLIENTS
 M:     Trond Myklebust <Trond.Myklebust@netapp.com>
index ee82f2fb65f0ab2c76135416ac8547f1d9c1fa3c..a1d4ede5b892d4516b294f91aca91633864e7d43 100644 (file)
@@ -96,6 +96,7 @@ static struct usb_device_id btusb_table[] = {
        { USB_DEVICE(0x0c10, 0x0000) },
 
        /* Broadcom BCM20702A0 */
+       { USB_DEVICE(0x0b05, 0x17b5) },
        { USB_DEVICE(0x04ca, 0x2003) },
        { USB_DEVICE(0x0489, 0xe042) },
        { USB_DEVICE(0x413c, 0x8197) },
index 99b9ddf21273b2244b2a8f9e03847a68a736bb61..77fa4286e5e98d2034fcbda6c0d786c3b455c50e 100644 (file)
@@ -379,7 +379,7 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
                 manifest_sync_timeout);
 
        if (!size) {
-               dev_printk(KERN_ERR, &udev->dev, "FW buffer length invalid!\n");
+               dev_err(&udev->dev, "FW buffer length invalid!\n");
                return -EINVAL;
        }
 
@@ -391,8 +391,8 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
                if (need_dfu_state) {
                        ret = at76_dfu_get_state(udev, &dfu_state);
                        if (ret < 0) {
-                               dev_printk(KERN_ERR, &udev->dev,
-                                          "cannot get DFU state: %d\n", ret);
+                               dev_err(&udev->dev,
+                                       "cannot get DFU state: %d\n", ret);
                                goto exit;
                        }
                        need_dfu_state = 0;
@@ -407,9 +407,9 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
                                dfu_timeout = at76_get_timeout(&dfu_stat_buf);
                                need_dfu_state = 0;
                        } else
-                               dev_printk(KERN_ERR, &udev->dev,
-                                          "at76_dfu_get_status returned %d\n",
-                                          ret);
+                               dev_err(&udev->dev,
+                                       "at76_dfu_get_status returned %d\n",
+                                       ret);
                        break;
 
                case STATE_DFU_DOWNLOAD_BUSY:
@@ -438,9 +438,9 @@ static int at76_usbdfu_download(struct usb_device *udev, u8 *buf, u32 size,
                        blockno++;
 
                        if (ret != bsize)
-                               dev_printk(KERN_ERR, &udev->dev,
-                                          "at76_load_int_fw_block "
-                                          "returned %d\n", ret);
+                               dev_err(&udev->dev,
+                                       "at76_load_int_fw_block returned %d\n",
+                                       ret);
                        need_dfu_state = 1;
                        break;
 
@@ -1255,8 +1255,7 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
        at76_dbg(DBG_DEVSTART, "opmode %d", op_mode);
 
        if (op_mode != OPMODE_NORMAL_NIC_WITHOUT_FLASH) {
-               dev_printk(KERN_ERR, &udev->dev, "unexpected opmode %d\n",
-                          op_mode);
+               dev_err(&udev->dev, "unexpected opmode %d\n", op_mode);
                return -EINVAL;
        }
 
@@ -1275,9 +1274,9 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
                         size, bsize, blockno);
                ret = at76_load_ext_fw_block(udev, blockno, block, bsize);
                if (ret != bsize) {
-                       dev_printk(KERN_ERR, &udev->dev,
-                                  "loading %dth firmware block failed: %d\n",
-                                  blockno, ret);
+                       dev_err(&udev->dev,
+                               "loading %dth firmware block failed: %d\n",
+                               blockno, ret);
                        goto exit;
                }
                buf += bsize;
@@ -1293,8 +1292,8 @@ static int at76_load_external_fw(struct usb_device *udev, struct fwentry *fwe)
 exit:
        kfree(block);
        if (ret < 0)
-               dev_printk(KERN_ERR, &udev->dev,
-                          "downloading external firmware failed: %d\n", ret);
+               dev_err(&udev->dev,
+                       "downloading external firmware failed: %d\n", ret);
        return ret;
 }
 
@@ -1308,8 +1307,8 @@ static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)
                                   need_remap ? 0 : 2 * HZ);
 
        if (ret < 0) {
-               dev_printk(KERN_ERR, &udev->dev,
-                          "downloading internal fw failed with %d\n", ret);
+               dev_err(&udev->dev,
+                       "downloading internal fw failed with %d\n", ret);
                goto exit;
        }
 
@@ -1319,8 +1318,8 @@ static int at76_load_internal_fw(struct usb_device *udev, struct fwentry *fwe)
        if (need_remap) {
                ret = at76_remap(udev);
                if (ret < 0) {
-                       dev_printk(KERN_ERR, &udev->dev,
-                                  "sending REMAP failed with %d\n", ret);
+                       dev_err(&udev->dev,
+                               "sending REMAP failed with %d\n", ret);
                        goto exit;
                }
        }
@@ -1555,11 +1554,10 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev,
        at76_dbg(DBG_FW, "downloading firmware %s", fwe->fwname);
        ret = request_firmware(&fwe->fw, fwe->fwname, &udev->dev);
        if (ret < 0) {
-               dev_printk(KERN_ERR, &udev->dev, "firmware %s not found!\n",
-                          fwe->fwname);
-               dev_printk(KERN_ERR, &udev->dev,
-                          "you may need to download the firmware from "
-                          "http://developer.berlios.de/projects/at76c503a/\n");
+               dev_err(&udev->dev, "firmware %s not found!\n",
+                       fwe->fwname);
+               dev_err(&udev->dev,
+                       "you may need to download the firmware from http://developer.berlios.de/projects/at76c503a/\n");
                goto exit;
        }
 
@@ -1567,17 +1565,17 @@ static struct fwentry *at76_load_firmware(struct usb_device *udev,
        fwh = (struct at76_fw_header *)(fwe->fw->data);
 
        if (fwe->fw->size <= sizeof(*fwh)) {
-               dev_printk(KERN_ERR, &udev->dev,
-                          "firmware is too short (0x%zx)\n", fwe->fw->size);
+               dev_err(&udev->dev,
+                       "firmware is too short (0x%zx)\n", fwe->fw->size);
                goto exit;
        }
 
        /* CRC currently not checked */
        fwe->board_type = le32_to_cpu(fwh->board_type);
        if (fwe->board_type != board_type) {
-               dev_printk(KERN_ERR, &udev->dev,
-                          "board type mismatch, requested %u, got %u\n",
-                          board_type, fwe->board_type);
+               dev_err(&udev->dev,
+                       "board type mismatch, requested %u, got %u\n",
+                       board_type, fwe->board_type);
                goto exit;
        }
 
@@ -2150,8 +2148,7 @@ static int at76_alloc_urbs(struct at76_priv *priv,
        }
 
        if (!ep_in || !ep_out) {
-               dev_printk(KERN_ERR, &interface->dev,
-                          "bulk endpoints missing\n");
+               dev_err(&interface->dev, "bulk endpoints missing\n");
                return -ENXIO;
        }
 
@@ -2161,15 +2158,14 @@ static int at76_alloc_urbs(struct at76_priv *priv,
        priv->rx_urb = usb_alloc_urb(0, GFP_KERNEL);
        priv->tx_urb = usb_alloc_urb(0, GFP_KERNEL);
        if (!priv->rx_urb || !priv->tx_urb) {
-               dev_printk(KERN_ERR, &interface->dev, "cannot allocate URB\n");
+               dev_err(&interface->dev, "cannot allocate URB\n");
                return -ENOMEM;
        }
 
        buffer_size = sizeof(struct at76_tx_buffer) + MAX_PADDING_SIZE;
        priv->bulk_out_buffer = kmalloc(buffer_size, GFP_KERNEL);
        if (!priv->bulk_out_buffer) {
-               dev_printk(KERN_ERR, &interface->dev,
-                          "cannot allocate output buffer\n");
+               dev_err(&interface->dev, "cannot allocate output buffer\n");
                return -ENOMEM;
        }
 
@@ -2230,8 +2226,7 @@ static int at76_init_new_device(struct at76_priv *priv,
        /* MAC address */
        ret = at76_get_hw_config(priv);
        if (ret < 0) {
-               dev_printk(KERN_ERR, &interface->dev,
-                          "cannot get MAC address\n");
+               dev_err(&interface->dev, "cannot get MAC address\n");
                goto exit;
        }
 
@@ -2358,8 +2353,8 @@ static int at76_probe(struct usb_interface *interface,
           we get 204 with 2.4.23, Fiberline FL-WL240u (505A+RFMD2958) ??? */
 
        if (op_mode == OPMODE_HW_CONFIG_MODE) {
-               dev_printk(KERN_ERR, &interface->dev,
-                          "cannot handle a device in HW_CONFIG_MODE\n");
+               dev_err(&interface->dev,
+                       "cannot handle a device in HW_CONFIG_MODE\n");
                ret = -EBUSY;
                goto error;
        }
@@ -2371,9 +2366,9 @@ static int at76_probe(struct usb_interface *interface,
                           "downloading internal firmware\n");
                ret = at76_load_internal_fw(udev, fwe);
                if (ret < 0) {
-                       dev_printk(KERN_ERR, &interface->dev,
-                                  "error %d downloading internal firmware\n",
-                                  ret);
+                       dev_err(&interface->dev,
+                               "error %d downloading internal firmware\n",
+                               ret);
                        goto error;
                }
                usb_put_dev(udev);
@@ -2408,8 +2403,8 @@ static int at76_probe(struct usb_interface *interface,
                /* Re-check firmware version */
                ret = at76_get_mib(udev, MIB_FW_VERSION, &fwv, sizeof(fwv));
                if (ret < 0) {
-                       dev_printk(KERN_ERR, &interface->dev,
-                                  "error %d getting firmware version\n", ret);
+                       dev_err(&interface->dev,
+                               "error %d getting firmware version\n", ret);
                        goto error;
                }
        }
@@ -2449,7 +2444,7 @@ static void at76_disconnect(struct usb_interface *interface)
 
        wiphy_info(priv->hw->wiphy, "disconnecting\n");
        at76_delete_device(priv);
-       dev_printk(KERN_INFO, &interface->dev, "disconnected\n");
+       dev_info(&interface->dev, "disconnected\n");
 }
 
 /* Structure for registering this driver with the USB subsystem */
index f782b6e502bf0f6101af213e7ec12784d3344262..7157f7d311c5e001a2e071231d50755fc7a9c3cb 100644 (file)
@@ -50,18 +50,19 @@ static void ar5523_read_reply(struct ar5523 *ar, struct ar5523_cmd_hdr *hdr,
                              struct ar5523_tx_cmd *cmd)
 {
        int dlen, olen;
-       u32 *rp;
+       __be32 *rp;
 
-       dlen = hdr->len - sizeof(*hdr);
+       dlen = be32_to_cpu(hdr->len) - sizeof(*hdr);
 
        if (dlen < 0) {
                WARN_ON(1);
                goto out;
        }
 
-       ar5523_dbg(ar, "Code = %d len = %d\n", hdr->code & 0xff, dlen);
+       ar5523_dbg(ar, "Code = %d len = %d\n", be32_to_cpu(hdr->code) & 0xff,
+                  dlen);
 
-       rp = (u32 *)(hdr + 1);
+       rp = (__be32 *)(hdr + 1);
        if (dlen >= sizeof(u32)) {
                olen = be32_to_cpu(rp[0]);
                dlen -= sizeof(u32);
@@ -95,6 +96,7 @@ static void ar5523_cmd_rx_cb(struct urb *urb)
        struct ar5523_tx_cmd *cmd = &ar->tx_cmd;
        struct ar5523_cmd_hdr *hdr = ar->rx_cmd_buf;
        int dlen;
+       u32 code, hdrlen;
 
        if (urb->status) {
                if (urb->status != -ESHUTDOWN)
@@ -110,15 +112,15 @@ static void ar5523_cmd_rx_cb(struct urb *urb)
        ar5523_dbg(ar, "%s code %02x priv %d\n", __func__,
                   be32_to_cpu(hdr->code) & 0xff, hdr->priv);
 
-       hdr->code = be32_to_cpu(hdr->code);
-       hdr->len = be32_to_cpu(hdr->len);
+       code = be32_to_cpu(hdr->code);
+       hdrlen = be32_to_cpu(hdr->len);
 
-       switch (hdr->code & 0xff) {
+       switch (code & 0xff) {
        default:
                /* reply to a read command */
                if (hdr->priv != AR5523_CMD_ID) {
                        ar5523_err(ar, "Unexpected command id: %02x\n",
-                                  hdr->code & 0xff);
+                                  code & 0xff);
                        goto skip;
                }
                ar5523_read_reply(ar, hdr, cmd);
@@ -147,7 +149,7 @@ static void ar5523_cmd_rx_cb(struct urb *urb)
        case WDCMSG_TARGET_START:
                /* This command returns a bogus id so it needs special
                   handling */
-               dlen = hdr->len - sizeof(*hdr);
+               dlen = hdrlen - sizeof(*hdr);
                if (dlen != (int)sizeof(u32)) {
                        ar5523_err(ar, "Invalid reply to WDCMSG_TARGET_START");
                        return;
@@ -303,7 +305,7 @@ static int ar5523_config(struct ar5523 *ar, u32 reg, u32 val)
 
        write.reg = cpu_to_be32(reg);
        write.len = cpu_to_be32(0);     /* 0 = single write */
-       *(u32 *)write.data = cpu_to_be32(val);
+       *(__be32 *)write.data = cpu_to_be32(val);
 
        error = ar5523_cmd_write(ar, WDCMSG_TARGET_SET_CONFIG, &write,
                                 3 * sizeof(u32), 0);
@@ -335,29 +337,30 @@ static int ar5523_get_status(struct ar5523 *ar, u32 which, void *odata,
                             int olen)
 {
        int error;
+       __be32 which_be;
 
-       which = cpu_to_be32(which);
+       which_be = cpu_to_be32(which);
        error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_STATUS,
-           &which, sizeof(which), odata, olen, AR5523_CMD_FLAG_MAGIC);
+           &which_be, sizeof(which_be), odata, olen, AR5523_CMD_FLAG_MAGIC);
        if (error != 0)
-               ar5523_err(ar, "could not read EEPROM offset 0x%02x\n",
-                          be32_to_cpu(which));
+               ar5523_err(ar, "could not read EEPROM offset 0x%02x\n", which);
        return error;
 }
 
 static int ar5523_get_capability(struct ar5523 *ar, u32 cap, u32 *val)
 {
        int error;
+       __be32 cap_be, val_be;
 
-       cap = cpu_to_be32(cap);
-       error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_CAPABILITY,
-           &cap, sizeof(cap), val, sizeof(u32), AR5523_CMD_FLAG_MAGIC);
+       cap_be = cpu_to_be32(cap);
+       error = ar5523_cmd_read(ar, WDCMSG_TARGET_GET_CAPABILITY, &cap_be,
+                               sizeof(cap_be), &val_be, sizeof(__be32),
+                               AR5523_CMD_FLAG_MAGIC);
        if (error != 0) {
-               ar5523_err(ar, "could not read capability %u\n",
-                          be32_to_cpu(cap));
+               ar5523_err(ar, "could not read capability %u\n", cap);
                return error;
        }
-       *val = be32_to_cpu(*val);
+       *val = be32_to_cpu(val_be);
        return error;
 }
 
@@ -1193,8 +1196,8 @@ static void ar5523_create_rateset(struct ar5523 *ar,
        if (!sta) {
                ar5523_info(ar, "STA not found. Cannot set rates\n");
                sta_rate_set = bss_conf->basic_rates;
-       }
-       sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band];
+       } else
+               sta_rate_set = sta->supp_rates[ar->hw->conf.channel->band];
 
        ar5523_dbg(ar, "sta rate_set = %08x\n", sta_rate_set);
 
@@ -1789,18 +1792,7 @@ static struct usb_driver ar5523_driver = {
        .disconnect     = ar5523_disconnect,
 };
 
-static int __init ar5523_init(void)
-{
-       return usb_register(&ar5523_driver);
-}
-
-static void __exit ar5523_exit(void)
-{
-       usb_deregister(&ar5523_driver);
-}
+module_usb_driver(ar5523_driver);
 
 MODULE_LICENSE("Dual BSD/GPL");
 MODULE_FIRMWARE(AR5523_FIRMWARE_FILE);
-
-module_init(ar5523_init);
-module_exit(ar5523_exit);
index a0e8bf460316289760859939c5e88df7d87dd1db..0fe2c803f48fbc38195e9639a6446755c4e886fe 100644 (file)
@@ -161,7 +161,7 @@ struct ar5523_rx_desc {
 
 struct ar5523_tx_desc {
        __be32  msglen;
-       __be32  msgid;          /* msg id (supplied by host) */
+       u32     msgid;          /* msg id (supplied by host) */
        __be32  type;           /* opcode: WDMSG_SEND or WDCMSG_FLUSH */
        __be32  txqid;          /* tx queue id and flags */
 #define        UATH_TXQID_MASK         0x0f
index aec33cc207fdbba47e67a6aa28a52ac19f4bfede..8e8bcc7a4805914ba64888ea683c13b3b76ddb0a 100644 (file)
@@ -236,17 +236,4 @@ static struct platform_driver ath_ahb_driver = {
        },
 };
 
-static int __init
-ath5k_ahb_init(void)
-{
-       return platform_driver_register(&ath_ahb_driver);
-}
-
-static void __exit
-ath5k_ahb_exit(void)
-{
-       platform_driver_unregister(&ath_ahb_driver);
-}
-
-module_init(ath5k_ahb_init);
-module_exit(ath5k_ahb_exit);
+module_platform_driver(ath_ahb_driver);
index 9f31cfa56cc092cfb9dca9647b3ef7aad62175c4..2fd5bab2e22a06a1fd3e574545961e5c09f41cc9 100644 (file)
@@ -511,8 +511,9 @@ ath5k_update_bssid_mask_and_opmode(struct ath5k_hw *ah,
                ath5k_vif_iter(&iter_data, vif->addr, vif);
 
        /* Get list of all active MAC addresses */
-       ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter,
-                                                  &iter_data);
+       ieee80211_iterate_active_interfaces_atomic(
+               ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               ath5k_vif_iter, &iter_data);
        memcpy(ah->bssidmask, iter_data.mask, ETH_ALEN);
 
        ah->opmode = iter_data.opmode;
@@ -1348,7 +1349,7 @@ ath5k_receive_frame(struct ath5k_hw *ah, struct sk_buff *skb,
         * right now, so it's not too bad...
         */
        rxs->mactime = ath5k_extend_tsf(ah, rs->rs_tstamp);
-       rxs->flag |= RX_FLAG_MACTIME_MPDU;
+       rxs->flag |= RX_FLAG_MACTIME_START;
 
        rxs->freq = ah->curchan->center_freq;
        rxs->band = ah->curchan->band;
@@ -3045,8 +3046,9 @@ ath5k_any_vif_assoc(struct ath5k_hw *ah)
        iter_data.need_set_hw_addr = false;
        iter_data.found_active = true;
 
-       ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter,
-                                                  &iter_data);
+       ieee80211_iterate_active_interfaces_atomic(
+               ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               ath5k_vif_iter, &iter_data);
        return iter_data.any_assoc;
 }
 
index 7a28538e6e05ba6c001e9b04aa913955a339ac44..1ea8c8795c8efeb1ed2e7b5ffacef643609a0885 100644 (file)
@@ -452,8 +452,9 @@ ath5k_configure_filter(struct ieee80211_hw *hw, unsigned int changed_flags,
        iter_data.hw_macaddr = NULL;
        iter_data.n_stas = 0;
        iter_data.need_set_hw_addr = false;
-       ieee80211_iterate_active_interfaces_atomic(ah->hw, ath5k_vif_iter,
-                                                  &iter_data);
+       ieee80211_iterate_active_interfaces_atomic(
+               ah->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               ath5k_vif_iter, &iter_data);
 
        /* Set up RX Filter */
        if (iter_data.n_stas > 1) {
index 0c2dd4771c365b798b7eb7b26eba79ddb4554c79..4084b1076286ebd20720a4276ff05bee3a8ac3c5 100644 (file)
@@ -789,9 +789,9 @@ ath5k_hw_nic_wakeup(struct ath5k_hw *ah, struct ieee80211_channel *channel)
                 * (I don't think it supports 44MHz) */
                /* On 2425 initvals TURBO_SHORT is not present */
                if (ah->ah_bwmode == AR5K_BWMODE_40MHZ) {
-                       turbo = AR5K_PHY_TURBO_MODE |
-                               (ah->ah_radio == AR5K_RF2425) ? 0 :
-                               AR5K_PHY_TURBO_SHORT;
+                       turbo = AR5K_PHY_TURBO_MODE;
+                       if (ah->ah_radio != AR5K_RF2425)
+                               turbo |= AR5K_PHY_TURBO_SHORT;
                } else if (ah->ah_bwmode != AR5K_BWMODE_DEFAULT) {
                        if (ah->ah_radio == AR5K_RF5413) {
                                mode |= (ah->ah_bwmode == AR5K_BWMODE_10MHZ) ?
index d755a5e7ed2036b9f7e237431413cd093fed07fc..26c4b72208597ba5c91f5be60ba3c753ce38c97f 100644 (file)
@@ -30,3 +30,12 @@ config ATH6KL_DEBUG
        depends on ATH6KL
        ---help---
          Enables debug support
+
+config ATH6KL_REGDOMAIN
+       bool "Atheros ath6kl regdomain support"
+       depends on ATH6KL
+       depends on CFG80211_CERTIFICATION_ONUS
+       ---help---
+         Enabling this makes it possible to change the regdomain in
+         the firmware. This can be only enabled if regulatory requirements
+         are taken into account.
index 8cae8886f17dc4eb667f107b49ef4af5c674369b..cab0ec0d5380afde712ac83bf23a2eaab514cbb8 100644 (file)
@@ -34,6 +34,7 @@ ath6kl_core-y += main.o
 ath6kl_core-y += txrx.o
 ath6kl_core-y += wmi.o
 ath6kl_core-y += core.o
+ath6kl_core-y += recovery.o
 ath6kl_core-$(CONFIG_NL80211_TESTMODE) += testmode.o
 
 obj-$(CONFIG_ATH6KL_SDIO) += ath6kl_sdio.o
index 277089963eb44acc2d99134f2920e8b4eed586c8..5516a8ccc3c6809589ff1d1fd8756859f504f7e9 100644 (file)
@@ -147,15 +147,15 @@ static bool __ath6kl_cfg80211_sscan_stop(struct ath6kl_vif *vif)
 {
        struct ath6kl *ar = vif->ar;
 
-       if (ar->state != ATH6KL_STATE_SCHED_SCAN)
+       if (!test_and_clear_bit(SCHED_SCANNING, &vif->flags))
                return false;
 
        del_timer_sync(&vif->sched_scan_timer);
 
-       ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
-                                          ATH6KL_HOST_MODE_AWAKE);
+       if (ar->state == ATH6KL_STATE_RECOVERY)
+               return true;
 
-       ar->state = ATH6KL_STATE_ON;
+       ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, false);
 
        return true;
 }
@@ -369,17 +369,13 @@ static int ath6kl_nliftype_to_drv_iftype(enum nl80211_iftype type, u8 *nw_type)
 {
        switch (type) {
        case NL80211_IFTYPE_STATION:
+       case NL80211_IFTYPE_P2P_CLIENT:
                *nw_type = INFRA_NETWORK;
                break;
        case NL80211_IFTYPE_ADHOC:
                *nw_type = ADHOC_NETWORK;
                break;
        case NL80211_IFTYPE_AP:
-               *nw_type = AP_NETWORK;
-               break;
-       case NL80211_IFTYPE_P2P_CLIENT:
-               *nw_type = INFRA_NETWORK;
-               break;
        case NL80211_IFTYPE_P2P_GO:
                *nw_type = AP_NETWORK;
                break;
@@ -1031,30 +1027,15 @@ static int ath6kl_cfg80211_scan(struct wiphy *wiphy,
 
        vif->scan_req = request;
 
-       if (test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
-                    ar->fw_capabilities)) {
-               /*
-                * If capable of doing P2P mgmt operations using
-                * station interface, send additional information like
-                * supported rates to advertise and xmit rates for
-                * probe requests
-                */
-               ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
-                                               WMI_LONG_SCAN, force_fg_scan,
-                                               false, 0,
-                                               ATH6KL_FG_SCAN_INTERVAL,
-                                               n_channels, channels,
-                                               request->no_cck,
-                                               request->rates);
-       } else {
-               ret = ath6kl_wmi_startscan_cmd(ar->wmi, vif->fw_vif_idx,
-                                               WMI_LONG_SCAN, force_fg_scan,
-                                               false, 0,
-                                               ATH6KL_FG_SCAN_INTERVAL,
-                                               n_channels, channels);
-       }
+       ret = ath6kl_wmi_beginscan_cmd(ar->wmi, vif->fw_vif_idx,
+                                      WMI_LONG_SCAN, force_fg_scan,
+                                      false, 0,
+                                      ATH6KL_FG_SCAN_INTERVAL,
+                                      n_channels, channels,
+                                      request->no_cck,
+                                      request->rates);
        if (ret) {
-               ath6kl_err("wmi_startscan_cmd failed\n");
+               ath6kl_err("failed to start scan: %d\n", ret);
                vif->scan_req = NULL;
        }
 
@@ -1093,15 +1074,18 @@ out:
 void ath6kl_cfg80211_ch_switch_notify(struct ath6kl_vif *vif, int freq,
                                      enum wmi_phy_mode mode)
 {
-       enum nl80211_channel_type type;
+       struct cfg80211_chan_def chandef;
 
        ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
                   "channel switch notify nw_type %d freq %d mode %d\n",
                   vif->nw_type, freq, mode);
 
-       type = (mode == WMI_11G_HT20) ? NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT;
+       cfg80211_chandef_create(&chandef,
+                               ieee80211_get_channel(vif->ar->wiphy, freq),
+                               (mode == WMI_11G_HT20) ?
+                                       NL80211_CHAN_HT20 : NL80211_CHAN_NO_HT);
 
-       cfg80211_ch_switch_notify(vif->ndev, freq, type);
+       cfg80211_ch_switch_notify(vif->ndev, &chandef);
 }
 
 static int ath6kl_cfg80211_add_key(struct wiphy *wiphy, struct net_device *ndev,
@@ -1384,11 +1368,8 @@ static int ath6kl_cfg80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
        return 0;
 }
 
-/*
- * The type nl80211_tx_power_setting replaces the following
- * data type from 2.6.36 onwards
-*/
 static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
+                                      struct wireless_dev *wdev,
                                       enum nl80211_tx_power_setting type,
                                       int mbm)
 {
@@ -1423,7 +1404,9 @@ static int ath6kl_cfg80211_set_txpower(struct wiphy *wiphy,
        return 0;
 }
 
-static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy, int *dbm)
+static int ath6kl_cfg80211_get_txpower(struct wiphy *wiphy,
+                                      struct wireless_dev *wdev,
+                                      int *dbm)
 {
        struct ath6kl *ar = (struct ath6kl *)wiphy_priv(wiphy);
        struct ath6kl_vif *vif;
@@ -1614,8 +1597,8 @@ static int ath6kl_cfg80211_join_ibss(struct wiphy *wiphy,
        vif->ssid_len = ibss_param->ssid_len;
        memcpy(vif->ssid, ibss_param->ssid, vif->ssid_len);
 
-       if (ibss_param->channel)
-               vif->ch_hint = ibss_param->channel->center_freq;
+       if (ibss_param->chandef.chan)
+               vif->ch_hint = ibss_param->chandef.chan->center_freq;
 
        if (ibss_param->channel_fixed) {
                /*
@@ -1889,7 +1872,7 @@ static int ath6kl_wow_usr(struct ath6kl *ar, struct ath6kl_vif *vif,
                          struct cfg80211_wowlan *wow, u32 *filter)
 {
        int ret, pos;
-       u8 mask[WOW_MASK_SIZE];
+       u8 mask[WOW_PATTERN_SIZE];
        u16 i;
 
        /* Configure the patterns that we received from the user. */
@@ -2107,33 +2090,16 @@ static int ath6kl_cfg80211_host_sleep(struct ath6kl *ar, struct ath6kl_vif *vif)
        return ret;
 }
 
-static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+static int ath6kl_wow_suspend_vif(struct ath6kl_vif *vif,
+                                 struct cfg80211_wowlan *wow, u32 *filter)
 {
+       struct ath6kl *ar = vif->ar;
        struct in_device *in_dev;
        struct in_ifaddr *ifa;
-       struct ath6kl_vif *vif;
        int ret;
-       u32 filter = 0;
        u16 i, bmiss_time;
-       u8 index = 0;
        __be32 ips[MAX_IP_ADDRS];
-
-       /* The FW currently can't support multi-vif WoW properly. */
-       if (ar->num_vif > 1)
-               return -EIO;
-
-       vif = ath6kl_vif_first(ar);
-       if (!vif)
-               return -EIO;
-
-       if (!ath6kl_cfg80211_ready(vif))
-               return -EIO;
-
-       if (!test_bit(CONNECTED, &vif->flags))
-               return -ENOTCONN;
-
-       if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
-               return -EINVAL;
+       u8 index = 0;
 
        if (!test_bit(NETDEV_MCAST_ALL_ON, &vif->flags) &&
            test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
@@ -2155,7 +2121,7 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
         * the user.
         */
        if (wow)
-               ret = ath6kl_wow_usr(ar, vif, wow, &filter);
+               ret = ath6kl_wow_usr(ar, vif, wow, filter);
        else if (vif->nw_type == AP_NETWORK)
                ret = ath6kl_wow_ap(ar, vif);
        else
@@ -2190,12 +2156,10 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
                        return ret;
        }
 
-       ar->state = ATH6KL_STATE_SUSPENDING;
-
        /* Setup own IP addr for ARP agent. */
        in_dev = __in_dev_get_rtnl(vif->ndev);
        if (!in_dev)
-               goto skip_arp;
+               return 0;
 
        ifa = in_dev->ifa_list;
        memset(&ips, 0, sizeof(ips));
@@ -2218,41 +2182,61 @@ static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
                return ret;
        }
 
-skip_arp:
-       ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
+       return ret;
+}
+
+static int ath6kl_wow_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
+{
+       struct ath6kl_vif *first_vif, *vif;
+       int ret = 0;
+       u32 filter = 0;
+       bool connected = false;
+
+       /* enter / leave wow suspend on first vif always */
+       first_vif = ath6kl_vif_first(ar);
+       if (WARN_ON(unlikely(!first_vif)) ||
+           !ath6kl_cfg80211_ready(first_vif))
+               return -EIO;
+
+       if (wow && (wow->n_patterns > WOW_MAX_FILTERS_PER_LIST))
+               return -EINVAL;
+
+       /* install filters for each connected vif */
+       spin_lock_bh(&ar->list_lock);
+       list_for_each_entry(vif, &ar->vif_list, list) {
+               if (!test_bit(CONNECTED, &vif->flags) ||
+                   !ath6kl_cfg80211_ready(vif))
+                       continue;
+               connected = true;
+
+               ret = ath6kl_wow_suspend_vif(vif, wow, &filter);
+               if (ret)
+                       break;
+       }
+       spin_unlock_bh(&ar->list_lock);
+
+       if (!connected)
+               return -ENOTCONN;
+       else if (ret)
+               return ret;
+
+       ar->state = ATH6KL_STATE_SUSPENDING;
+
+       ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, first_vif->fw_vif_idx,
                                          ATH6KL_WOW_MODE_ENABLE,
                                          filter,
                                          WOW_HOST_REQ_DELAY);
        if (ret)
                return ret;
 
-       ret = ath6kl_cfg80211_host_sleep(ar, vif);
-       if (ret)
-               return ret;
-
-       return 0;
+       return ath6kl_cfg80211_host_sleep(ar, first_vif);
 }
 
-static int ath6kl_wow_resume(struct ath6kl *ar)
+static int ath6kl_wow_resume_vif(struct ath6kl_vif *vif)
 {
-       struct ath6kl_vif *vif;
+       struct ath6kl *ar = vif->ar;
        int ret;
 
-       vif = ath6kl_vif_first(ar);
-       if (!vif)
-               return -EIO;
-
-       ar->state = ATH6KL_STATE_RESUMING;
-
-       ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
-                                                ATH6KL_HOST_MODE_AWAKE);
-       if (ret) {
-               ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
-                           ret);
-               ar->state = ATH6KL_STATE_WOW;
-               return ret;
-       }
-
        if (vif->nw_type != AP_NETWORK) {
                ret = ath6kl_wmi_scanparams_cmd(ar->wmi, vif->fw_vif_idx,
                                                0, 0, 0, 0, 0, 0, 3, 0, 0, 0);
@@ -2270,13 +2254,11 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
                        return ret;
        }
 
-       ar->state = ATH6KL_STATE_ON;
-
        if (!test_bit(NETDEV_MCAST_ALL_OFF, &vif->flags) &&
            test_bit(ATH6KL_FW_CAPABILITY_WOW_MULTICAST_FILTER,
                     ar->fw_capabilities)) {
                ret = ath6kl_wmi_mcast_filter_cmd(vif->ar->wmi,
-                                       vif->fw_vif_idx, true);
+                                                 vif->fw_vif_idx, true);
                if (ret)
                        return ret;
        }
@@ -2286,6 +2268,48 @@ static int ath6kl_wow_resume(struct ath6kl *ar)
        return 0;
 }
 
+static int ath6kl_wow_resume(struct ath6kl *ar)
+{
+       struct ath6kl_vif *vif;
+       int ret;
+
+       vif = ath6kl_vif_first(ar);
+       if (WARN_ON(unlikely(!vif)) ||
+           !ath6kl_cfg80211_ready(vif))
+               return -EIO;
+
+       ar->state = ATH6KL_STATE_RESUMING;
+
+       ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
+                                                ATH6KL_HOST_MODE_AWAKE);
+       if (ret) {
+               ath6kl_warn("Failed to configure host sleep mode for wow resume: %d\n",
+                           ret);
+               goto cleanup;
+       }
+
+       spin_lock_bh(&ar->list_lock);
+       list_for_each_entry(vif, &ar->vif_list, list) {
+               if (!test_bit(CONNECTED, &vif->flags) ||
+                   !ath6kl_cfg80211_ready(vif))
+                       continue;
+               ret = ath6kl_wow_resume_vif(vif);
+               if (ret)
+                       break;
+       }
+       spin_unlock_bh(&ar->list_lock);
+
+       if (ret)
+               goto cleanup;
+
+       ar->state = ATH6KL_STATE_ON;
+       return 0;
+
+cleanup:
+       ar->state = ATH6KL_STATE_WOW;
+       return ret;
+}
+
 static int ath6kl_cfg80211_deepsleep_suspend(struct ath6kl *ar)
 {
        struct ath6kl_vif *vif;
@@ -2422,13 +2446,6 @@ int ath6kl_cfg80211_suspend(struct ath6kl *ar,
 
                break;
 
-       case ATH6KL_CFG_SUSPEND_SCHED_SCAN:
-               /*
-                * Nothing needed for schedule scan, firmware is already in
-                * wow mode and sleeping most of the time.
-                */
-               break;
-
        default:
                break;
        }
@@ -2476,9 +2493,6 @@ int ath6kl_cfg80211_resume(struct ath6kl *ar)
                }
                break;
 
-       case ATH6KL_STATE_SCHED_SCAN:
-               break;
-
        default:
                break;
        }
@@ -2495,14 +2509,23 @@ static int __ath6kl_cfg80211_suspend(struct wiphy *wiphy,
 {
        struct ath6kl *ar = wiphy_priv(wiphy);
 
+       ath6kl_recovery_suspend(ar);
+
        return ath6kl_hif_suspend(ar, wow);
 }
 
 static int __ath6kl_cfg80211_resume(struct wiphy *wiphy)
 {
        struct ath6kl *ar = wiphy_priv(wiphy);
+       int err;
+
+       err = ath6kl_hif_resume(ar);
+       if (err)
+               return err;
 
-       return ath6kl_hif_resume(ar);
+       ath6kl_recovery_resume(ar);
+
+       return 0;
 }
 
 /*
@@ -2739,6 +2762,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
        int res;
        int i, ret;
        u16 rsn_capab = 0;
+       int inactivity_timeout = 0;
 
        ath6kl_dbg(ATH6KL_DBG_WLAN_CFG, "%s:\n", __func__);
 
@@ -2857,7 +2881,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
        p.ssid_len = vif->ssid_len;
        memcpy(p.ssid, vif->ssid, vif->ssid_len);
        p.dot11_auth_mode = vif->dot11_auth_mode;
-       p.ch = cpu_to_le16(info->channel->center_freq);
+       p.ch = cpu_to_le16(info->chandef.chan->center_freq);
 
        /* Enable uAPSD support by default */
        res = ath6kl_wmi_ap_set_apsd(ar->wmi, vif->fw_vif_idx, true);
@@ -2875,14 +2899,22 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
        }
 
        if (info->inactivity_timeout) {
+
+               inactivity_timeout = info->inactivity_timeout;
+
+               if (ar->hw.flags & ATH6KL_HW_AP_INACTIVITY_MINS)
+                       inactivity_timeout = DIV_ROUND_UP(inactivity_timeout,
+                                                         60);
+
                res = ath6kl_wmi_set_inact_period(ar->wmi, vif->fw_vif_idx,
-                                                 info->inactivity_timeout);
+                                                 inactivity_timeout);
                if (res < 0)
                        return res;
        }
 
-       if (ath6kl_set_htcap(vif, info->channel->band,
-                            info->channel_type != NL80211_CHAN_NO_HT))
+       if (ath6kl_set_htcap(vif, info->chandef.chan->band,
+                            cfg80211_get_chandef_type(&info->chandef)
+                                       != NL80211_CHAN_NO_HT))
                return -EIO;
 
        /*
@@ -2898,6 +2930,7 @@ static int ath6kl_start_ap(struct wiphy *wiphy, struct net_device *dev,
                                            WLAN_EID_RSN, WMI_RSN_IE_CAPB,
                                            (const u8 *) &rsn_capab,
                                            sizeof(rsn_capab));
+               vif->rsn_capab = rsn_capab;
                if (res < 0)
                        return res;
        }
@@ -2977,7 +3010,6 @@ static int ath6kl_change_station(struct wiphy *wiphy, struct net_device *dev,
 static int ath6kl_remain_on_channel(struct wiphy *wiphy,
                                    struct wireless_dev *wdev,
                                    struct ieee80211_channel *chan,
-                                   enum nl80211_channel_type channel_type,
                                    unsigned int duration,
                                    u64 *cookie)
 {
@@ -3136,10 +3168,8 @@ static bool ath6kl_is_p2p_go_ssid(const u8 *buf, size_t len)
 
 static int ath6kl_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                          struct ieee80211_channel *chan, bool offchan,
-                         enum nl80211_channel_type channel_type,
-                         bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, bool no_cck,
-                         bool dont_wait_for_ack, u64 *cookie)
+                         unsigned int wait, const u8 *buf, size_t len,
+                         bool no_cck, bool dont_wait_for_ack, u64 *cookie)
 {
        struct ath6kl_vif *vif = ath6kl_vif_from_wdev(wdev);
        struct ath6kl *ar = ath6kl_priv(vif->ndev);
@@ -3211,7 +3241,7 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
        struct ath6kl *ar = ath6kl_priv(dev);
        struct ath6kl_vif *vif = netdev_priv(dev);
        u16 interval;
-       int ret;
+       int ret, rssi_thold;
 
        if (ar->state != ATH6KL_STATE_ON)
                return -EIO;
@@ -3219,10 +3249,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
        if (vif->sme_state != SME_DISCONNECTED)
                return -EBUSY;
 
-       /* The FW currently can't support multi-vif WoW properly. */
-       if (ar->num_vif > 1)
-               return -EIO;
-
        ath6kl_cfg80211_scan_complete_event(vif, true);
 
        ret = ath6kl_set_probed_ssids(ar, vif, request->ssids,
@@ -3244,6 +3270,23 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
                        return ret;
        }
 
+       if (test_bit(ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
+                    ar->fw_capabilities)) {
+               if (request->rssi_thold <= NL80211_SCAN_RSSI_THOLD_OFF)
+                       rssi_thold = 0;
+               else if (request->rssi_thold < -127)
+                       rssi_thold = -127;
+               else
+                       rssi_thold = request->rssi_thold;
+
+               ret = ath6kl_wmi_set_rssi_filter_cmd(ar->wmi, vif->fw_vif_idx,
+                                                    rssi_thold);
+               if (ret) {
+                       ath6kl_err("failed to set RSSI threshold for scan\n");
+                       return ret;
+               }
+       }
+
        /* fw uses seconds, also make sure that it's >0 */
        interval = max_t(u16, 1, request->interval / 1000);
 
@@ -3251,15 +3294,6 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
                                  interval, interval,
                                  vif->bg_scan_period, 0, 0, 0, 3, 0, 0, 0);
 
-       ret = ath6kl_wmi_set_wow_mode_cmd(ar->wmi, vif->fw_vif_idx,
-                                         ATH6KL_WOW_MODE_ENABLE,
-                                         WOW_FILTER_SSID,
-                                         WOW_HOST_REQ_DELAY);
-       if (ret) {
-               ath6kl_warn("Failed to enable wow with ssid filter: %d\n", ret);
-               return ret;
-       }
-
        /* this also clears IE in fw if it's not set */
        ret = ath6kl_wmi_set_appie_cmd(ar->wmi, vif->fw_vif_idx,
                                       WMI_FRAME_PROBE_REQ,
@@ -3270,17 +3304,13 @@ static int ath6kl_cfg80211_sscan_start(struct wiphy *wiphy,
                return ret;
        }
 
-       ret = ath6kl_wmi_set_host_sleep_mode_cmd(ar->wmi, vif->fw_vif_idx,
-                                                ATH6KL_HOST_MODE_ASLEEP);
-       if (ret) {
-               ath6kl_warn("Failed to enable host sleep mode for sched scan: %d\n",
-                           ret);
+       ret = ath6kl_wmi_enable_sched_scan_cmd(ar->wmi, vif->fw_vif_idx, true);
+       if (ret)
                return ret;
-       }
 
-       ar->state = ATH6KL_STATE_SCHED_SCAN;
+       set_bit(SCHED_SCANNING, &vif->flags);
 
-       return ret;
+       return 0;
 }
 
 static int ath6kl_cfg80211_sscan_stop(struct wiphy *wiphy,
@@ -3309,6 +3339,27 @@ static int ath6kl_cfg80211_set_bitrate(struct wiphy *wiphy,
                                           mask);
 }
 
+static int ath6kl_cfg80211_set_txe_config(struct wiphy *wiphy,
+                                         struct net_device *dev,
+                                         u32 rate, u32 pkts, u32 intvl)
+{
+       struct ath6kl *ar = ath6kl_priv(dev);
+       struct ath6kl_vif *vif = netdev_priv(dev);
+
+       if (vif->nw_type != INFRA_NETWORK ||
+           !test_bit(ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY, ar->fw_capabilities))
+               return -EOPNOTSUPP;
+
+       if (vif->sme_state != SME_CONNECTED)
+               return -ENOTCONN;
+
+       /* save this since the firmware won't report the interval */
+       vif->txe_intvl = intvl;
+
+       return ath6kl_wmi_set_txe_notify(ar->wmi, vif->fw_vif_idx,
+                                        rate, pkts, intvl);
+}
+
 static const struct ieee80211_txrx_stypes
 ath6kl_mgmt_stypes[NUM_NL80211_IFTYPES] = {
        [NL80211_IFTYPE_STATION] = {
@@ -3375,6 +3426,7 @@ static struct cfg80211_ops ath6kl_cfg80211_ops = {
        .sched_scan_start = ath6kl_cfg80211_sscan_start,
        .sched_scan_stop = ath6kl_cfg80211_sscan_stop,
        .set_bitrate_mask = ath6kl_cfg80211_set_bitrate,
+       .set_cqm_txe_config = ath6kl_cfg80211_set_txe_config,
 };
 
 void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
@@ -3395,16 +3447,22 @@ void ath6kl_cfg80211_stop(struct ath6kl_vif *vif)
                break;
        }
 
-       if (test_bit(CONNECTED, &vif->flags) ||
-           test_bit(CONNECT_PEND, &vif->flags))
+       if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
+           (test_bit(CONNECTED, &vif->flags) ||
+           test_bit(CONNECT_PEND, &vif->flags)))
                ath6kl_wmi_disconnect_cmd(vif->ar->wmi, vif->fw_vif_idx);
 
        vif->sme_state = SME_DISCONNECTED;
        clear_bit(CONNECTED, &vif->flags);
        clear_bit(CONNECT_PEND, &vif->flags);
 
+       /* Stop netdev queues, needed during recovery */
+       netif_stop_queue(vif->ndev);
+       netif_carrier_off(vif->ndev);
+
        /* disable scanning */
-       if (ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
+       if (vif->ar->state != ATH6KL_STATE_RECOVERY &&
+           ath6kl_wmi_scanparams_cmd(vif->ar->wmi, vif->fw_vif_idx, 0xFFFF,
                                      0, 0, 0, 0, 0, 0, 0, 0, 0) != 0)
                ath6kl_warn("failed to disable scan during stop\n");
 
@@ -3416,7 +3474,7 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
        struct ath6kl_vif *vif;
 
        vif = ath6kl_vif_first(ar);
-       if (!vif) {
+       if (!vif && ar->state != ATH6KL_STATE_RECOVERY) {
                /* save the current power mode before enabling power save */
                ar->wmi->saved_pwr_mode = ar->wmi->pwr_mode;
 
@@ -3434,6 +3492,56 @@ void ath6kl_cfg80211_stop_all(struct ath6kl *ar)
                ath6kl_cfg80211_stop(vif);
 }
 
+static int ath6kl_cfg80211_reg_notify(struct wiphy *wiphy,
+                                     struct regulatory_request *request)
+{
+       struct ath6kl *ar = wiphy_priv(wiphy);
+       u32 rates[IEEE80211_NUM_BANDS];
+       int ret, i;
+
+       ath6kl_dbg(ATH6KL_DBG_WLAN_CFG,
+                  "cfg reg_notify %c%c%s%s initiator %d hint_type %d\n",
+                  request->alpha2[0], request->alpha2[1],
+                  request->intersect ? " intersect" : "",
+                  request->processed ? " processed" : "",
+                  request->initiator, request->user_reg_hint_type);
+
+       /*
+        * As firmware is not able intersect regdoms, we can only listen to
+        * cellular hints.
+        */
+       if (request->user_reg_hint_type != NL80211_USER_REG_HINT_CELL_BASE)
+               return -EOPNOTSUPP;
+
+       ret = ath6kl_wmi_set_regdomain_cmd(ar->wmi, request->alpha2);
+       if (ret) {
+               ath6kl_err("failed to set regdomain: %d\n", ret);
+               return ret;
+       }
+
+       /*
+        * Firmware will apply the regdomain change only after a scan is
+        * issued and it will send a WMI_REGDOMAIN_EVENTID when it has been
+        * changed.
+        */
+
+       for (i = 0; i < IEEE80211_NUM_BANDS; i++)
+               if (wiphy->bands[i])
+                       rates[i] = (1 << wiphy->bands[i]->n_bitrates) - 1;
+
+
+       ret = ath6kl_wmi_beginscan_cmd(ar->wmi, 0, WMI_LONG_SCAN, false,
+                                      false, 0, ATH6KL_FG_SCAN_INTERVAL,
+                                      0, NULL, false, rates);
+       if (ret) {
+               ath6kl_err("failed to start scan for a regdomain change: %d\n",
+                          ret);
+               return ret;
+       }
+
+       return 0;
+}
+
 static int ath6kl_cfg80211_vif_init(struct ath6kl_vif *vif)
 {
        vif->aggr_cntxt = aggr_init(vif);
@@ -3506,9 +3614,13 @@ struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
        vif->htcap[IEEE80211_BAND_5GHZ].ht_enable = true;
 
        memcpy(ndev->dev_addr, ar->mac_addr, ETH_ALEN);
-       if (fw_vif_idx != 0)
+       if (fw_vif_idx != 0) {
                ndev->dev_addr[0] = (ndev->dev_addr[0] ^ (1 << fw_vif_idx)) |
                                     0x2;
+               if (test_bit(ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR,
+                            ar->fw_capabilities))
+                       ndev->dev_addr[4] ^= 0x80;
+       }
 
        init_netdev(ndev);
 
@@ -3562,6 +3674,12 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
                                          BIT(NL80211_IFTYPE_P2P_CLIENT);
        }
 
+       if (config_enabled(CONFIG_ATH6KL_REGDOMAIN) &&
+           test_bit(ATH6KL_FW_CAPABILITY_REGDOMAIN, ar->fw_capabilities)) {
+               wiphy->reg_notifier = ath6kl_cfg80211_reg_notify;
+               ar->wiphy->features |= NL80211_FEATURE_CELL_BASE_REG_HINTS;
+       }
+
        /* max num of ssids that can be probed during scanning */
        wiphy->max_scan_ssids = MAX_PROBED_SSIDS;
 
@@ -3607,7 +3725,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
                ath6kl_band_5ghz.ht_cap.ht_supported = false;
        }
 
-       if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES) {
+       if (ar->hw.flags & ATH6KL_HW_64BIT_RATES) {
                ath6kl_band_2ghz.ht_cap.mcs.rx_mask[0] = 0xff;
                ath6kl_band_5ghz.ht_cap.mcs.rx_mask[0] = 0xff;
                ath6kl_band_2ghz.ht_cap.mcs.rx_mask[1] = 0xff;
@@ -3646,7 +3764,7 @@ int ath6kl_cfg80211_init(struct ath6kl *ar)
                            WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL |
                            WIPHY_FLAG_AP_PROBE_RESP_OFFLOAD;
 
-       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN, ar->fw_capabilities))
+       if (test_bit(ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2, ar->fw_capabilities))
                ar->wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
 
        if (test_bit(ATH6KL_FW_CAPABILITY_INACTIVITY_TIMEOUT,
index 780f77775a9152ca078922cbd2a7754c9a019d24..e5e70f3a8ca866f1e4c1c40c8e9ff04914b49692 100644 (file)
@@ -22,7 +22,6 @@ enum ath6kl_cfg_suspend_mode {
        ATH6KL_CFG_SUSPEND_DEEPSLEEP,
        ATH6KL_CFG_SUSPEND_CUTPOWER,
        ATH6KL_CFG_SUSPEND_WOW,
-       ATH6KL_CFG_SUSPEND_SCHED_SCAN,
 };
 
 struct wireless_dev *ath6kl_interface_add(struct ath6kl *ar, const char *name,
index 82c4dd2a960e5077f7a9f11e1201cabf3b75be04..4b46adbe8c923b7dd410c919dc3cbc289541ea4f 100644 (file)
@@ -33,6 +33,8 @@ static unsigned int wow_mode;
 static unsigned int uart_debug;
 static unsigned int ath6kl_p2p;
 static unsigned int testmode;
+static unsigned int recovery_enable;
+static unsigned int heart_beat_poll;
 
 module_param(debug_mask, uint, 0644);
 module_param(suspend_mode, uint, 0644);
@@ -40,6 +42,12 @@ module_param(wow_mode, uint, 0644);
 module_param(uart_debug, uint, 0644);
 module_param(ath6kl_p2p, uint, 0644);
 module_param(testmode, uint, 0644);
+module_param(recovery_enable, uint, 0644);
+module_param(heart_beat_poll, uint, 0644);
+MODULE_PARM_DESC(recovery_enable, "Enable recovery from firmware error");
+MODULE_PARM_DESC(heart_beat_poll, "Enable fw error detection periodic"   \
+                "polling. This also specifies the polling interval in"  \
+                "msecs. Set reocvery_enable for this to be effective");
 
 void ath6kl_core_tx_complete(struct ath6kl *ar, struct sk_buff *skb)
 {
@@ -202,6 +210,17 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type)
        ath6kl_dbg(ATH6KL_DBG_TRC, "%s: name=%s dev=0x%p, ar=0x%p\n",
                   __func__, wdev->netdev->name, wdev->netdev, ar);
 
+       ar->fw_recovery.enable = !!recovery_enable;
+       if (!ar->fw_recovery.enable)
+               return ret;
+
+       if (heart_beat_poll &&
+           test_bit(ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL,
+                    ar->fw_capabilities))
+               ar->fw_recovery.hb_poll = heart_beat_poll;
+
+       ath6kl_recovery_init(ar);
+
        return ret;
 
 err_rxbuf_cleanup:
@@ -291,6 +310,8 @@ void ath6kl_core_cleanup(struct ath6kl *ar)
 {
        ath6kl_hif_power_off(ar);
 
+       ath6kl_recovery_cleanup(ar);
+
        destroy_workqueue(ar->ath6kl_wq);
 
        if (ar->htc_target)
index cec49a31029aa9711682d1ede1f862c58aa8ed30..189d8faf8c87f8bd36b16d8d40e568aa90fc98f5 100644 (file)
@@ -115,6 +115,27 @@ enum ath6kl_fw_capability {
         */
        ATH6KL_FW_CAPABILITY_SCHED_SCAN_MATCH_LIST,
 
+       /* Firmware supports filtering BSS results by RSSI */
+       ATH6KL_FW_CAPABILITY_RSSI_SCAN_THOLD,
+
+       /* FW sets mac_addr[4] ^= 0x80 for newly created interfaces */
+       ATH6KL_FW_CAPABILITY_CUSTOM_MAC_ADDR,
+
+       /* Firmware supports TX error rate notification */
+       ATH6KL_FW_CAPABILITY_TX_ERR_NOTIFY,
+
+       /* supports WMI_SET_REGDOMAIN_CMDID command */
+       ATH6KL_FW_CAPABILITY_REGDOMAIN,
+
+       /* Firmware supports sched scan decoupled from host sleep */
+       ATH6KL_FW_CAPABILITY_SCHED_SCAN_V2,
+
+       /*
+        * Firmware capability for hang detection through heart beat
+        * challenge messages.
+        */
+       ATH6KL_FW_CAPABILITY_HEART_BEAT_POLL,
+
        /* this needs to be last */
        ATH6KL_FW_CAPABILITY_MAX,
 };
@@ -128,11 +149,15 @@ struct ath6kl_fw_ie {
 };
 
 enum ath6kl_hw_flags {
-       ATH6KL_HW_FLAG_64BIT_RATES      = BIT(0),
+       ATH6KL_HW_64BIT_RATES           = BIT(0),
+       ATH6KL_HW_AP_INACTIVITY_MINS    = BIT(1),
+       ATH6KL_HW_MAP_LP_ENDPOINT       = BIT(2),
+       ATH6KL_HW_SDIO_CRC_ERROR_WAR    = BIT(3),
 };
 
 #define ATH6KL_FW_API2_FILE "fw-2.bin"
 #define ATH6KL_FW_API3_FILE "fw-3.bin"
+#define ATH6KL_FW_API4_FILE "fw-4.bin"
 
 /* AR6003 1.0 definitions */
 #define AR6003_HW_1_0_VERSION                 0x300002ba
@@ -186,6 +211,13 @@ enum ath6kl_hw_flags {
 #define AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE \
        AR6004_HW_1_2_FW_DIR "/bdata.bin"
 
+/* AR6004 1.3 definitions */
+#define AR6004_HW_1_3_VERSION                  0x31c8088a
+#define AR6004_HW_1_3_FW_DIR                   "ath6k/AR6004/hw1.3"
+#define AR6004_HW_1_3_FIRMWARE_FILE            "fw.ram.bin"
+#define AR6004_HW_1_3_BOARD_DATA_FILE          "ath6k/AR6004/hw1.3/bdata.bin"
+#define AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE  "ath6k/AR6004/hw1.3/bdata.bin"
+
 /* Per STA data, used in AP mode */
 #define STA_PS_AWAKE           BIT(0)
 #define        STA_PS_SLEEP            BIT(1)
@@ -536,6 +568,7 @@ enum ath6kl_vif_state {
        HOST_SLEEP_MODE_CMD_PROCESSED,
        NETDEV_MCAST_ALL_ON,
        NETDEV_MCAST_ALL_OFF,
+       SCHED_SCANNING,
 };
 
 struct ath6kl_vif {
@@ -580,11 +613,13 @@ struct ath6kl_vif {
        u16 assoc_bss_beacon_int;
        u16 listen_intvl_t;
        u16 bmiss_time_t;
+       u32 txe_intvl;
        u16 bg_scan_period;
        u8 assoc_bss_dtim_period;
        struct net_device_stats net_stats;
        struct target_stats target_stats;
        struct wmi_connect_cmd profile;
+       u16 rsn_capab;
 
        struct list_head mc_filter;
 };
@@ -609,6 +644,7 @@ enum ath6kl_dev_state {
        SKIP_SCAN,
        ROAM_TBL_PEND,
        FIRST_BOOT,
+       RECOVERY_CLEANUP,
 };
 
 enum ath6kl_state {
@@ -619,7 +655,16 @@ enum ath6kl_state {
        ATH6KL_STATE_DEEPSLEEP,
        ATH6KL_STATE_CUTPOWER,
        ATH6KL_STATE_WOW,
-       ATH6KL_STATE_SCHED_SCAN,
+       ATH6KL_STATE_RECOVERY,
+};
+
+/* Fw error recovery */
+#define ATH6KL_HB_RESP_MISS_THRES      5
+
+enum ath6kl_fw_err {
+       ATH6KL_FW_ASSERT,
+       ATH6KL_FW_HB_RESP_FAILURE,
+       ATH6KL_FW_EP_FULL,
 };
 
 struct ath6kl {
@@ -679,6 +724,7 @@ struct ath6kl {
        struct ath6kl_req_key ap_mode_bkey;
        struct sk_buff_head mcastpsq;
        u32 want_ch_switch;
+       u16 last_ch;
 
        /*
         * FIXME: protects access to mcastpsq but is actually useless as
@@ -764,6 +810,17 @@ struct ath6kl {
 
        bool wiphy_registered;
 
+       struct ath6kl_fw_recovery {
+               struct work_struct recovery_work;
+               unsigned long err_reason;
+               unsigned long hb_poll;
+               struct timer_list hb_timer;
+               u32 seq_num;
+               bool hb_pending;
+               u8 hb_misscnt;
+               bool enable;
+       } fw_recovery;
+
 #ifdef CONFIG_ATH6KL_DEBUG
        struct {
                struct sk_buff_head fwlog_queue;
@@ -899,4 +956,12 @@ int ath6kl_core_init(struct ath6kl *ar, enum ath6kl_htc_type htc_type);
 void ath6kl_core_cleanup(struct ath6kl *ar);
 void ath6kl_core_destroy(struct ath6kl *ar);
 
+/* Fw error recovery */
+void ath6kl_init_hw_restart(struct ath6kl *ar);
+void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason);
+void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie);
+void ath6kl_recovery_init(struct ath6kl *ar);
+void ath6kl_recovery_cleanup(struct ath6kl *ar);
+void ath6kl_recovery_suspend(struct ath6kl *ar);
+void ath6kl_recovery_resume(struct ath6kl *ar);
 #endif /* CORE_H */
index 49639d8266c28a25a186cfe148c70a5ef0c3535f..f97cd4ead543fdd239220372cc6846539343d1c6 100644 (file)
@@ -44,6 +44,7 @@ enum ATH6K_DEBUG_MASK {
        ATH6KL_DBG_SUSPEND      = BIT(20),
        ATH6KL_DBG_USB          = BIT(21),
        ATH6KL_DBG_USB_BULK     = BIT(22),
+       ATH6KL_DBG_RECOVERY     = BIT(23),
        ATH6KL_DBG_ANY          = 0xffffffff  /* enable all logs */
 };
 
index 68ed6c2665b73387cefbc1edf0985a94b7ad36a6..a6b614421fa409814e1662a78df1507da904b970 100644 (file)
@@ -136,6 +136,7 @@ static int ath6kl_hif_proc_dbg_intr(struct ath6kl_device *dev)
 
        ath6kl_hif_dump_fw_crash(dev->ar);
        ath6kl_read_fwlogs(dev->ar);
+       ath6kl_recovery_err_notify(dev->ar, ATH6KL_FW_ASSERT);
 
        return ret;
 }
@@ -338,8 +339,7 @@ static int ath6kl_hif_proc_err_intr(struct ath6kl_device *dev)
        status = hif_read_write_sync(dev->ar, ERROR_INT_STATUS_ADDRESS,
                                     reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
 
-       if (status)
-               WARN_ON(1);
+       WARN_ON(status);
 
        return status;
 }
@@ -383,8 +383,7 @@ static int ath6kl_hif_proc_cpu_intr(struct ath6kl_device *dev)
        status = hif_read_write_sync(dev->ar, CPU_INT_STATUS_ADDRESS,
                                     reg_buf, 4, HIF_WR_SYNC_BYTE_FIX);
 
-       if (status)
-               WARN_ON(1);
+       WARN_ON(status);
 
        return status;
 }
@@ -695,11 +694,6 @@ int ath6kl_hif_setup(struct ath6kl_device *dev)
        ath6kl_dbg(ATH6KL_DBG_HIF, "hif block size %d mbox addr 0x%x\n",
                   dev->htc_cnxt->block_sz, dev->ar->mbox_info.htc_addr);
 
-       /* usb doesn't support enabling interrupts */
-       /* FIXME: remove check once USB support is implemented */
-       if (dev->ar->hif_type == ATH6KL_HIF_TYPE_USB)
-               return 0;
-
        status = ath6kl_hif_disable_intrs(dev);
 
 fail_setup:
index cd0e1ba410d6ac3050fa5bb3fd35f99451492238..fbb78dfe078f692ad94c34d80bf9dbf7ec2e3a06 100644 (file)
@@ -2492,7 +2492,8 @@ static int ath6kl_htc_mbox_conn_service(struct htc_target *target,
                max_msg_sz = le16_to_cpu(resp_msg->max_msg_sz);
        }
 
-       if (assigned_ep >= ENDPOINT_MAX || !max_msg_sz) {
+       if (WARN_ON_ONCE(assigned_ep == ENDPOINT_UNUSED ||
+                        assigned_ep >= ENDPOINT_MAX || !max_msg_sz)) {
                status = -ENOMEM;
                goto fail_tx;
        }
@@ -2655,12 +2656,6 @@ static int ath6kl_htc_mbox_wait_target(struct htc_target *target)
        struct htc_service_connect_resp resp;
        int status;
 
-       /* FIXME: remove once USB support is implemented */
-       if (target->dev->ar->hif_type == ATH6KL_HIF_TYPE_USB) {
-               ath6kl_err("HTC doesn't support USB yet. Patience!\n");
-               return -EOPNOTSUPP;
-       }
-
        /* we should be getting 1 control message that the target is ready */
        packet = htc_wait_for_ctrl_msg(target);
 
@@ -2890,9 +2885,7 @@ static void ath6kl_htc_mbox_cleanup(struct htc_target *target)
 {
        struct htc_packet *packet, *tmp_packet;
 
-       /* FIXME: remove check once USB support is implemented */
-       if (target->dev->ar->hif_type != ATH6KL_HIF_TYPE_USB)
-               ath6kl_hif_cleanup_scatter(target->dev->ar);
+       ath6kl_hif_cleanup_scatter(target->dev->ar);
 
        list_for_each_entry_safe(packet, tmp_packet,
                                 &target->free_ctrl_txbuf, list) {
index f9626c723693ca84e7c3efbaccd0fa47de49916b..ba6bd497b78701f4d53a939b7343e766ca0088a0 100644 (file)
@@ -374,9 +374,8 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
                                packet = list_first_entry(txq,
                                                          struct htc_packet,
                                                          list);
-                               list_del(&packet->list);
-                               /* insert into local queue */
-                               list_add_tail(&packet->list, &send_queue);
+                               /* move to local queue */
+                               list_move_tail(&packet->list, &send_queue);
                        }
 
                        /*
@@ -399,11 +398,10 @@ static enum htc_send_queue_result htc_try_send(struct htc_target *target,
                                         * for cleanup */
                                } else {
                                        /* callback wants to keep this packet,
-                                        * remove from caller's queue */
-                                       list_del(&packet->list);
-                                       /* put it in the send queue */
-                                       list_add_tail(&packet->list,
-                                                     &send_queue);
+                                        * move from caller's queue to the send
+                                        * queue */
+                                       list_move_tail(&packet->list,
+                                                      &send_queue);
                                }
 
                        }
index f90b5db741cf74c6784a9dc0a6a100d2b7a59f08..f21fa322e5ca3e7245a994ebce2dc0ce48c82c7a 100644 (file)
@@ -42,7 +42,7 @@ static const struct ath6kl_hw hw_list[] = {
                .reserved_ram_size              = 6912,
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
-               .flags                          = 0,
+               .flags                          = ATH6KL_HW_SDIO_CRC_ERROR_WAR,
 
                /* hw2.0 needs override address hardcoded */
                .app_start_override_addr        = 0x944C00,
@@ -68,7 +68,7 @@ static const struct ath6kl_hw hw_list[] = {
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 8,
                .testscript_addr                = 0x57ef74,
-               .flags                          = 0,
+               .flags                          = ATH6KL_HW_SDIO_CRC_ERROR_WAR,
 
                .fw = {
                        .dir            = AR6003_HW_2_1_1_FW_DIR,
@@ -93,7 +93,8 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x433900,
                .refclk_hz                      = 26000000,
                .uarttx_pin                     = 11,
-               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
+               .flags                          = ATH6KL_HW_64BIT_RATES |
+                                                 ATH6KL_HW_AP_INACTIVITY_MINS,
 
                .fw = {
                        .dir            = AR6004_HW_1_0_FW_DIR,
@@ -113,8 +114,8 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x43d400,
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
-               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
-
+               .flags                          = ATH6KL_HW_64BIT_RATES |
+                                                 ATH6KL_HW_AP_INACTIVITY_MINS,
                .fw = {
                        .dir            = AR6004_HW_1_1_FW_DIR,
                        .fw             = AR6004_HW_1_1_FIRMWARE_FILE,
@@ -133,7 +134,8 @@ static const struct ath6kl_hw hw_list[] = {
                .board_addr                     = 0x435c00,
                .refclk_hz                      = 40000000,
                .uarttx_pin                     = 11,
-               .flags                          = ATH6KL_HW_FLAG_64BIT_RATES,
+               .flags                          = ATH6KL_HW_64BIT_RATES |
+                                                 ATH6KL_HW_AP_INACTIVITY_MINS,
 
                .fw = {
                        .dir            = AR6004_HW_1_2_FW_DIR,
@@ -142,6 +144,28 @@ static const struct ath6kl_hw hw_list[] = {
                .fw_board               = AR6004_HW_1_2_BOARD_DATA_FILE,
                .fw_default_board       = AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE,
        },
+       {
+               .id                             = AR6004_HW_1_3_VERSION,
+               .name                           = "ar6004 hw 1.3",
+               .dataset_patch_addr             = 0x437860,
+               .app_load_addr                  = 0x1234,
+               .board_ext_data_addr            = 0x437000,
+               .reserved_ram_size              = 7168,
+               .board_addr                     = 0x436400,
+               .refclk_hz                      = 40000000,
+               .uarttx_pin                     = 11,
+               .flags                          = ATH6KL_HW_64BIT_RATES |
+                                                 ATH6KL_HW_AP_INACTIVITY_MINS |
+                                                 ATH6KL_HW_MAP_LP_ENDPOINT,
+
+               .fw = {
+                       .dir            = AR6004_HW_1_3_FW_DIR,
+                       .fw             = AR6004_HW_1_3_FIRMWARE_FILE,
+               },
+
+               .fw_board               = AR6004_HW_1_3_BOARD_DATA_FILE,
+               .fw_default_board       = AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE,
+       },
 };
 
 /*
@@ -337,7 +361,7 @@ static int ath6kl_init_service_ep(struct ath6kl *ar)
        if (ath6kl_connectservice(ar, &connect, "WMI DATA BK"))
                return -EIO;
 
-       /* connect to Video service, map this to to HI PRI */
+       /* connect to Video service, map this to HI PRI */
        connect.svc_id = WMI_DATA_VI_SVC;
        if (ath6kl_connectservice(ar, &connect, "WMI DATA VI"))
                return -EIO;
@@ -1088,6 +1112,12 @@ int ath6kl_init_fetch_firmwares(struct ath6kl *ar)
        if (ret)
                return ret;
 
+       ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API4_FILE);
+       if (ret == 0) {
+               ar->fw_api = 4;
+               goto out;
+       }
+
        ret = ath6kl_fetch_fw_apin(ar, ATH6KL_FW_API3_FILE);
        if (ret == 0) {
                ar->fw_api = 3;
@@ -1401,8 +1431,7 @@ static int ath6kl_init_upload(struct ath6kl *ar)
                return status;
 
        /* WAR to avoid SDIO CRC err */
-       if (ar->version.target_ver == AR6003_HW_2_0_VERSION ||
-           ar->version.target_ver == AR6003_HW_2_1_1_VERSION) {
+       if (ar->hw.flags & ATH6KL_HW_SDIO_CRC_ERROR_WAR) {
                ath6kl_err("temporary war to avoid sdio crc error\n");
 
                param = 0x28;
@@ -1520,7 +1549,7 @@ static const char *ath6kl_init_get_hif_name(enum ath6kl_hif_type type)
        return NULL;
 }
 
-int ath6kl_init_hw_start(struct ath6kl *ar)
+static int __ath6kl_init_hw_start(struct ath6kl *ar)
 {
        long timeleft;
        int ret, i;
@@ -1616,8 +1645,6 @@ int ath6kl_init_hw_start(struct ath6kl *ar)
                        goto err_htc_stop;
        }
 
-       ar->state = ATH6KL_STATE_ON;
-
        return 0;
 
 err_htc_stop:
@@ -1630,7 +1657,18 @@ err_power_off:
        return ret;
 }
 
-int ath6kl_init_hw_stop(struct ath6kl *ar)
+int ath6kl_init_hw_start(struct ath6kl *ar)
+{
+       int err;
+
+       err = __ath6kl_init_hw_start(ar);
+       if (err)
+               return err;
+       ar->state = ATH6KL_STATE_ON;
+       return 0;
+}
+
+static int __ath6kl_init_hw_stop(struct ath6kl *ar)
 {
        int ret;
 
@@ -1646,11 +1684,37 @@ int ath6kl_init_hw_stop(struct ath6kl *ar)
        if (ret)
                ath6kl_warn("failed to power off hif: %d\n", ret);
 
-       ar->state = ATH6KL_STATE_OFF;
+       return 0;
+}
 
+int ath6kl_init_hw_stop(struct ath6kl *ar)
+{
+       int err;
+
+       err = __ath6kl_init_hw_stop(ar);
+       if (err)
+               return err;
+       ar->state = ATH6KL_STATE_OFF;
        return 0;
 }
 
+void ath6kl_init_hw_restart(struct ath6kl *ar)
+{
+       clear_bit(WMI_READY, &ar->flag);
+
+       ath6kl_cfg80211_stop_all(ar);
+
+       if (__ath6kl_init_hw_stop(ar)) {
+               ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to stop during fw error recovery\n");
+               return;
+       }
+
+       if (__ath6kl_init_hw_start(ar)) {
+               ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Failed to restart during fw error recovery\n");
+               return;
+       }
+}
+
 /* FIXME: move this to cfg80211.c and rename to ath6kl_cfg80211_vif_stop() */
 void ath6kl_cleanup_vif(struct ath6kl_vif *vif, bool wmi_ready)
 {
index c189e28e86a9bbfaebb7f81a32291801d51fa1f7..bd50b6b7b49267665e8854e388dd068fab63707b 100644 (file)
@@ -293,13 +293,17 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
        }
 
        address = TARG_VTOP(ar->target_type, debug_hdr_addr);
-       ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
+       ret = ath6kl_diag_read(ar, address, &debug_hdr, sizeof(debug_hdr));
+       if (ret)
+               goto out;
 
        address = TARG_VTOP(ar->target_type,
                            le32_to_cpu(debug_hdr.dbuf_addr));
        firstbuf = address;
        dropped = le32_to_cpu(debug_hdr.dropped);
-       ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
+       ret = ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
+       if (ret)
+               goto out;
 
        loop = 100;
 
@@ -322,7 +326,8 @@ int ath6kl_read_fwlogs(struct ath6kl *ar)
 
                address = TARG_VTOP(ar->target_type,
                                    le32_to_cpu(debug_buf.next));
-               ath6kl_diag_read(ar, address, &debug_buf, sizeof(debug_buf));
+               ret = ath6kl_diag_read(ar, address, &debug_buf,
+                                      sizeof(debug_buf));
                if (ret)
                        goto out;
 
@@ -436,12 +441,9 @@ void ath6kl_connect_ap_mode_bss(struct ath6kl_vif *vif, u16 channel)
                break;
        }
 
-       if (ar->want_ch_switch & (1 << vif->fw_vif_idx)) {
-               ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
+       if (ar->last_ch != channel)
                /* we actually don't know the phymode, default to HT20 */
-               ath6kl_cfg80211_ch_switch_notify(vif, channel,
-                                                WMI_11G_HT20);
-       }
+               ath6kl_cfg80211_ch_switch_notify(vif, channel, WMI_11G_HT20);
 
        ath6kl_wmi_bssfilter_cmd(ar->wmi, vif->fw_vif_idx, NONE_BSS_FILTER, 0);
        set_bit(CONNECTED, &vif->flags);
@@ -606,6 +608,18 @@ static int ath6kl_commit_ch_switch(struct ath6kl_vif *vif, u16 channel)
 
        switch (vif->nw_type) {
        case AP_NETWORK:
+               /*
+                * reconfigure any saved RSN IE capabilites in the beacon /
+                * probe response to stay in sync with the supplicant.
+                */
+               if (vif->rsn_capab &&
+                   test_bit(ATH6KL_FW_CAPABILITY_RSN_CAP_OVERRIDE,
+                            ar->fw_capabilities))
+                       ath6kl_wmi_set_ie_cmd(ar->wmi, vif->fw_vif_idx,
+                                             WLAN_EID_RSN, WMI_RSN_IE_CAPB,
+                                             (const u8 *) &vif->rsn_capab,
+                                             sizeof(vif->rsn_capab));
+
                return ath6kl_wmi_ap_profile_commit(ar->wmi, vif->fw_vif_idx,
                                                    &vif->profile);
        default:
@@ -628,6 +642,9 @@ static void ath6kl_check_ch_switch(struct ath6kl *ar, u16 channel)
                if (ar->want_ch_switch & (1 << vif->fw_vif_idx))
                        res = ath6kl_commit_ch_switch(vif, channel);
 
+               /* if channel switch failed, oh well we tried */
+               ar->want_ch_switch &= ~(1 << vif->fw_vif_idx);
+
                if (res)
                        ath6kl_err("channel switch failed nw_type %d res %d\n",
                                   vif->nw_type, res);
@@ -981,8 +998,25 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
        if (vif->nw_type == AP_NETWORK) {
                /* disconnect due to other STA vif switching channels */
                if (reason == BSS_DISCONNECTED &&
-                   prot_reason_status == WMI_AP_REASON_STA_ROAM)
+                   prot_reason_status == WMI_AP_REASON_STA_ROAM) {
                        ar->want_ch_switch |= 1 << vif->fw_vif_idx;
+                       /* bail back to this channel if STA vif fails connect */
+                       ar->last_ch = le16_to_cpu(vif->profile.ch);
+               }
+
+               if (prot_reason_status == WMI_AP_REASON_MAX_STA) {
+                       /* send max client reached notification to user space */
+                       cfg80211_conn_failed(vif->ndev, bssid,
+                                            NL80211_CONN_FAIL_MAX_CLIENTS,
+                                            GFP_KERNEL);
+               }
+
+               if (prot_reason_status == WMI_AP_REASON_ACL) {
+                       /* send blocked client notification to user space */
+                       cfg80211_conn_failed(vif->ndev, bssid,
+                                            NL80211_CONN_FAIL_BLOCKED_CLIENT,
+                                            GFP_KERNEL);
+               }
 
                if (!ath6kl_remove_sta(ar, bssid, prot_reason_status))
                        return;
@@ -1041,6 +1075,9 @@ void ath6kl_disconnect_event(struct ath6kl_vif *vif, u8 reason, u8 *bssid,
                }
        }
 
+       /* restart disconnected concurrent vifs waiting for new channel */
+       ath6kl_check_ch_switch(ar, ar->last_ch);
+
        /* update connect & link status atomically */
        spin_lock_bh(&vif->if_lock);
        clear_bit(CONNECTED, &vif->flags);
diff --git a/drivers/net/wireless/ath/ath6kl/recovery.c b/drivers/net/wireless/ath/ath6kl/recovery.c
new file mode 100644 (file)
index 0000000..3a8d5e9
--- /dev/null
@@ -0,0 +1,160 @@
+/*
+ * Copyright (c) 2012 Qualcomm Atheros, Inc.
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR
+ * ANY SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN
+ * ACTION OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF
+ * OR IN CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+#include "core.h"
+#include "cfg80211.h"
+#include "debug.h"
+
+static void ath6kl_recovery_work(struct work_struct *work)
+{
+       struct ath6kl *ar = container_of(work, struct ath6kl,
+                                        fw_recovery.recovery_work);
+
+       ar->state = ATH6KL_STATE_RECOVERY;
+
+       del_timer_sync(&ar->fw_recovery.hb_timer);
+
+       ath6kl_init_hw_restart(ar);
+
+       ar->state = ATH6KL_STATE_ON;
+       clear_bit(WMI_CTRL_EP_FULL, &ar->flag);
+
+       ar->fw_recovery.err_reason = 0;
+
+       if (ar->fw_recovery.hb_poll)
+               mod_timer(&ar->fw_recovery.hb_timer, jiffies +
+                         msecs_to_jiffies(ar->fw_recovery.hb_poll));
+}
+
+void ath6kl_recovery_err_notify(struct ath6kl *ar, enum ath6kl_fw_err reason)
+{
+       if (!ar->fw_recovery.enable)
+               return;
+
+       ath6kl_dbg(ATH6KL_DBG_RECOVERY, "Fw error detected, reason:%d\n",
+                  reason);
+
+       set_bit(reason, &ar->fw_recovery.err_reason);
+
+       if (!test_bit(RECOVERY_CLEANUP, &ar->flag) &&
+           ar->state != ATH6KL_STATE_RECOVERY)
+               queue_work(ar->ath6kl_wq, &ar->fw_recovery.recovery_work);
+}
+
+void ath6kl_recovery_hb_event(struct ath6kl *ar, u32 cookie)
+{
+       if (cookie == ar->fw_recovery.seq_num)
+               ar->fw_recovery.hb_pending = false;
+}
+
+static void ath6kl_recovery_hb_timer(unsigned long data)
+{
+       struct ath6kl *ar = (struct ath6kl *) data;
+       int err;
+
+       if (test_bit(RECOVERY_CLEANUP, &ar->flag) ||
+           (ar->state == ATH6KL_STATE_RECOVERY))
+               return;
+
+       if (ar->fw_recovery.hb_pending)
+               ar->fw_recovery.hb_misscnt++;
+       else
+               ar->fw_recovery.hb_misscnt = 0;
+
+       if (ar->fw_recovery.hb_misscnt > ATH6KL_HB_RESP_MISS_THRES) {
+               ar->fw_recovery.hb_misscnt = 0;
+               ar->fw_recovery.seq_num = 0;
+               ar->fw_recovery.hb_pending = false;
+               ath6kl_recovery_err_notify(ar, ATH6KL_FW_HB_RESP_FAILURE);
+               return;
+       }
+
+       ar->fw_recovery.seq_num++;
+       ar->fw_recovery.hb_pending = true;
+
+       err = ath6kl_wmi_get_challenge_resp_cmd(ar->wmi,
+                                               ar->fw_recovery.seq_num, 0);
+       if (err)
+               ath6kl_warn("Failed to send hb challenge request, err:%d\n",
+                           err);
+
+       mod_timer(&ar->fw_recovery.hb_timer, jiffies +
+                 msecs_to_jiffies(ar->fw_recovery.hb_poll));
+}
+
+void ath6kl_recovery_init(struct ath6kl *ar)
+{
+       struct ath6kl_fw_recovery *recovery = &ar->fw_recovery;
+
+       clear_bit(RECOVERY_CLEANUP, &ar->flag);
+       INIT_WORK(&recovery->recovery_work, ath6kl_recovery_work);
+       recovery->seq_num = 0;
+       recovery->hb_misscnt = 0;
+       ar->fw_recovery.hb_pending = false;
+       ar->fw_recovery.hb_timer.function = ath6kl_recovery_hb_timer;
+       ar->fw_recovery.hb_timer.data = (unsigned long) ar;
+       init_timer_deferrable(&ar->fw_recovery.hb_timer);
+
+       if (ar->fw_recovery.hb_poll)
+               mod_timer(&ar->fw_recovery.hb_timer, jiffies +
+                         msecs_to_jiffies(ar->fw_recovery.hb_poll));
+}
+
+void ath6kl_recovery_cleanup(struct ath6kl *ar)
+{
+       if (!ar->fw_recovery.enable)
+               return;
+
+       set_bit(RECOVERY_CLEANUP, &ar->flag);
+
+       del_timer_sync(&ar->fw_recovery.hb_timer);
+       cancel_work_sync(&ar->fw_recovery.recovery_work);
+}
+
+void ath6kl_recovery_suspend(struct ath6kl *ar)
+{
+       if (!ar->fw_recovery.enable)
+               return;
+
+       ath6kl_recovery_cleanup(ar);
+
+       if (!ar->fw_recovery.err_reason)
+               return;
+
+       /* Process pending fw error detection */
+       ar->fw_recovery.err_reason = 0;
+       WARN_ON(ar->state != ATH6KL_STATE_ON);
+       ar->state = ATH6KL_STATE_RECOVERY;
+       ath6kl_init_hw_restart(ar);
+       ar->state = ATH6KL_STATE_ON;
+}
+
+void ath6kl_recovery_resume(struct ath6kl *ar)
+{
+       if (!ar->fw_recovery.enable)
+               return;
+
+       clear_bit(RECOVERY_CLEANUP, &ar->flag);
+
+       if (!ar->fw_recovery.hb_poll)
+               return;
+
+       ar->fw_recovery.hb_pending = false;
+       ar->fw_recovery.seq_num = 0;
+       ar->fw_recovery.hb_misscnt = 0;
+       mod_timer(&ar->fw_recovery.hb_timer,
+                 jiffies + msecs_to_jiffies(ar->fw_recovery.hb_poll));
+}
index 05b95405f7b56131b4cbf49a66d165a8f661861e..d111980d44c0bb9b550b0733322b663a6842c6c8 100644 (file)
@@ -709,7 +709,7 @@ static int ath6kl_sdio_enable_scatter(struct ath6kl *ar)
 {
        struct ath6kl_sdio *ar_sdio = ath6kl_sdio_priv(ar);
        struct htc_target *target = ar->htc_target;
-       int ret;
+       int ret = 0;
        bool virt_scat = false;
 
        if (ar_sdio->scatter_enabled)
@@ -844,22 +844,6 @@ static int ath6kl_sdio_suspend(struct ath6kl *ar, struct cfg80211_wowlan *wow)
        bool try_deepsleep = false;
        int ret;
 
-       if (ar->state == ATH6KL_STATE_SCHED_SCAN) {
-               ath6kl_dbg(ATH6KL_DBG_SUSPEND, "sched scan is in progress\n");
-
-               ret = ath6kl_set_sdio_pm_caps(ar);
-               if (ret)
-                       goto cut_pwr;
-
-               ret =  ath6kl_cfg80211_suspend(ar,
-                                              ATH6KL_CFG_SUSPEND_SCHED_SCAN,
-                                              NULL);
-               if (ret)
-                       goto cut_pwr;
-
-               return 0;
-       }
-
        if (ar->suspend_mode == WLAN_POWER_STATE_WOW ||
            (!ar->suspend_mode && wow)) {
 
@@ -942,14 +926,14 @@ static int ath6kl_sdio_resume(struct ath6kl *ar)
        case ATH6KL_STATE_WOW:
                break;
 
-       case ATH6KL_STATE_SCHED_SCAN:
-               break;
-
        case ATH6KL_STATE_SUSPENDING:
                break;
 
        case ATH6KL_STATE_RESUMING:
                break;
+
+       case ATH6KL_STATE_RECOVERY:
+               break;
        }
 
        ath6kl_cfg80211_resume(ar);
@@ -1462,3 +1446,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_2_FW_DIR "/" AR6004_HW_1_2_FIRMWARE_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE);
index 7dfa0fd86d7b111ea06cbd1c85d673ba65717cb6..78b369286579dd954f98243a24e948db2a4f3c2b 100644 (file)
@@ -288,8 +288,16 @@ int ath6kl_control_tx(void *devt, struct sk_buff *skb,
        int status = 0;
        struct ath6kl_cookie *cookie = NULL;
 
-       if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW))
+       if (WARN_ON_ONCE(ar->state == ATH6KL_STATE_WOW)) {
+               dev_kfree_skb(skb);
                return -EACCES;
+       }
+
+       if (WARN_ON_ONCE(eid == ENDPOINT_UNUSED ||
+                        eid >= ENDPOINT_MAX)) {
+               status = -EINVAL;
+               goto fail_ctrl_tx;
+       }
 
        spin_lock_bh(&ar->lock);
 
@@ -591,6 +599,7 @@ enum htc_send_full_action ath6kl_tx_queue_full(struct htc_target *target,
                 */
                set_bit(WMI_CTRL_EP_FULL, &ar->flag);
                ath6kl_err("wmi ctrl ep is full\n");
+               ath6kl_recovery_err_notify(ar, ATH6KL_FW_EP_FULL);
                return action;
        }
 
@@ -695,22 +704,31 @@ void ath6kl_tx_complete(struct htc_target *target,
                                          list);
                list_del(&packet->list);
 
+               if (WARN_ON_ONCE(packet->endpoint == ENDPOINT_UNUSED ||
+                                packet->endpoint >= ENDPOINT_MAX))
+                       continue;
+
                ath6kl_cookie = (struct ath6kl_cookie *)packet->pkt_cntxt;
-               if (!ath6kl_cookie)
-                       goto fatal;
+               if (WARN_ON_ONCE(!ath6kl_cookie))
+                       continue;
 
                status = packet->status;
                skb = ath6kl_cookie->skb;
                eid = packet->endpoint;
                map_no = ath6kl_cookie->map_no;
 
-               if (!skb || !skb->data)
-                       goto fatal;
+               if (WARN_ON_ONCE(!skb || !skb->data)) {
+                       dev_kfree_skb(skb);
+                       ath6kl_free_cookie(ar, ath6kl_cookie);
+                       continue;
+               }
 
                __skb_queue_tail(&skb_queue, skb);
 
-               if (!status && (packet->act_len != skb->len))
-                       goto fatal;
+               if (WARN_ON_ONCE(!status && (packet->act_len != skb->len))) {
+                       ath6kl_free_cookie(ar, ath6kl_cookie);
+                       continue;
+               }
 
                ar->tx_pending[eid]--;
 
@@ -792,11 +810,6 @@ void ath6kl_tx_complete(struct htc_target *target,
                wake_up(&ar->event_wq);
 
        return;
-
-fatal:
-       WARN_ON(1);
-       spin_unlock_bh(&ar->lock);
-       return;
 }
 
 void ath6kl_tx_data_cleanup(struct ath6kl *ar)
@@ -885,8 +898,11 @@ void ath6kl_rx_refill(struct htc_target *target, enum htc_endpoint_id endpoint)
                        break;
 
                packet = (struct htc_packet *) skb->head;
-               if (!IS_ALIGNED((unsigned long) skb->data, 4))
+               if (!IS_ALIGNED((unsigned long) skb->data, 4)) {
+                       size_t len = skb_headlen(skb);
                        skb->data = PTR_ALIGN(skb->data - 4, 4);
+                       skb_set_tail_pointer(skb, len);
+               }
                set_htc_rxpkt_info(packet, skb, skb->data,
                                   ATH6KL_BUFFER_SIZE, endpoint);
                packet->skb = skb;
@@ -908,8 +924,11 @@ void ath6kl_refill_amsdu_rxbufs(struct ath6kl *ar, int count)
                        return;
 
                packet = (struct htc_packet *) skb->head;
-               if (!IS_ALIGNED((unsigned long) skb->data, 4))
+               if (!IS_ALIGNED((unsigned long) skb->data, 4)) {
+                       size_t len = skb_headlen(skb);
                        skb->data = PTR_ALIGN(skb->data - 4, 4);
+                       skb_set_tail_pointer(skb, len);
+               }
                set_htc_rxpkt_info(packet, skb, skb->data,
                                   ATH6KL_AMSDU_BUFFER_SIZE, 0);
                packet->skb = skb;
index 3740c3d6ab8832a89fa397ac0e4e903e81782f66..62bcc0d5bc23d73493694984cd7e8aa202291635 100644 (file)
@@ -185,9 +185,10 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
        for (i = 0; i < urb_cnt; i++) {
                urb_context = kzalloc(sizeof(struct ath6kl_urb_context),
                                      GFP_KERNEL);
-               if (urb_context == NULL)
-                       /* FIXME: set status to -ENOMEM */
-                       break;
+               if (urb_context == NULL) {
+                       status = -ENOMEM;
+                       goto fail_alloc_pipe_resources;
+               }
 
                urb_context->pipe = pipe;
 
@@ -204,6 +205,7 @@ static int ath6kl_usb_alloc_pipe_resources(struct ath6kl_usb_pipe *pipe,
                   pipe->logical_pipe_num, pipe->usb_pipe_handle,
                   pipe->urb_alloc);
 
+fail_alloc_pipe_resources:
        return status;
 }
 
@@ -803,7 +805,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
                *dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
                break;
        case WMI_DATA_VI_SVC:
-               *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
+
+               if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
+                       *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
+               else
+                       *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
                /*
                * Disable rxdata2 directly, it will be enabled
                * if FW enable rxdata2
@@ -811,7 +817,11 @@ static int ath6kl_usb_map_service_pipe(struct ath6kl *ar, u16 svc_id,
                *dl_pipe = ATH6KL_USB_PIPE_RX_DATA;
                break;
        case WMI_DATA_VO_SVC:
-               *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_HP;
+
+               if (ar->hw.flags & ATH6KL_HW_MAP_LP_ENDPOINT)
+                       *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_LP;
+               else
+                       *ul_pipe = ATH6KL_USB_PIPE_TX_DATA_MP;
                /*
                * Disable rxdata2 directly, it will be enabled
                * if FW enable rxdata2
@@ -1196,7 +1206,14 @@ static struct usb_driver ath6kl_usb_driver = {
 
 static int ath6kl_usb_init(void)
 {
-       usb_register(&ath6kl_usb_driver);
+       int ret;
+
+       ret = usb_register(&ath6kl_usb_driver);
+       if (ret) {
+               ath6kl_err("usb registration failed: %d\n", ret);
+               return ret;
+       }
+
        return 0;
 }
 
@@ -1220,3 +1237,6 @@ MODULE_FIRMWARE(AR6004_HW_1_1_DEFAULT_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_2_FIRMWARE_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_2_BOARD_DATA_FILE);
 MODULE_FIRMWARE(AR6004_HW_1_2_DEFAULT_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_3_FW_DIR "/" AR6004_HW_1_3_FIRMWARE_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_3_BOARD_DATA_FILE);
+MODULE_FIRMWARE(AR6004_HW_1_3_DEFAULT_BOARD_DATA_FILE);
index c30ab4b11d614c8188afc53d61ad3dee8b29a9ba..998f8b0f62fd59e4d6507216bf257f0ed4776dcf 100644 (file)
@@ -474,7 +474,7 @@ static int ath6kl_wmi_remain_on_chnl_event_rx(struct wmi *wmi, u8 *datap,
                return -EINVAL;
        }
        id = vif->last_roc_id;
-       cfg80211_ready_on_channel(&vif->wdev, id, chan, NL80211_CHAN_NO_HT,
+       cfg80211_ready_on_channel(&vif->wdev, id, chan,
                                  dur, GFP_ATOMIC);
 
        return 0;
@@ -513,8 +513,7 @@ static int ath6kl_wmi_cancel_remain_on_chnl_event_rx(struct wmi *wmi,
        else
                id = vif->last_roc_id; /* timeout on uncanceled r-o-c */
        vif->last_cancel_roc_id = 0;
-       cfg80211_remain_on_channel_expired(&vif->wdev, id, chan,
-                                          NL80211_CHAN_NO_HT, GFP_ATOMIC);
+       cfg80211_remain_on_channel_expired(&vif->wdev, id, chan, GFP_ATOMIC);
 
        return 0;
 }
@@ -936,8 +935,12 @@ static void ath6kl_wmi_regdomain_event(struct wmi *wmi, u8 *datap, int len)
 
                regpair = ath6kl_get_regpair((u16) reg_code);
                country = ath6kl_regd_find_country_by_rd((u16) reg_code);
-               ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
-                          regpair->regDmnEnum);
+               if (regpair)
+                       ath6kl_dbg(ATH6KL_DBG_WMI, "Regpair used: 0x%0x\n",
+                                  regpair->regDmnEnum);
+               else
+                       ath6kl_warn("Regpair not found reg_code 0x%0x\n",
+                                   reg_code);
        }
 
        if (country && wmi->parent_dev->wiphy_registered) {
@@ -1116,7 +1119,7 @@ static int ath6kl_wmi_bssinfo_event_rx(struct wmi *wmi, u8 *datap, int len,
         * the timer would not ever fire if the scan interval is short
         * enough.
         */
-       if (ar->state == ATH6KL_STATE_SCHED_SCAN &&
+       if (test_bit(SCHED_SCANNING, &vif->flags) &&
            !timer_pending(&vif->sched_scan_timer)) {
                mod_timer(&vif->sched_scan_timer, jiffies +
                          msecs_to_jiffies(ATH6KL_SCHED_SCAN_RESULT_DELAY));
@@ -1170,6 +1173,9 @@ static int ath6kl_wmi_bitrate_reply_rx(struct wmi *wmi, u8 *datap, int len)
                rate = RATE_AUTO;
        } else {
                index = reply->rate_index & 0x7f;
+               if (WARN_ON_ONCE(index > (RATE_MCS_7_40 + 1)))
+                       return -EINVAL;
+
                sgi = (reply->rate_index & 0x80) ? 1 : 0;
                rate = wmi_rate_tbl[index][sgi];
        }
@@ -1531,6 +1537,68 @@ static int ath6kl_wmi_cac_event_rx(struct wmi *wmi, u8 *datap, int len,
        return 0;
 }
 
+static int ath6kl_wmi_txe_notify_event_rx(struct wmi *wmi, u8 *datap, int len,
+                                         struct ath6kl_vif *vif)
+{
+       struct wmi_txe_notify_event *ev;
+       u32 rate, pkts;
+
+       if (len < sizeof(*ev))
+               return -EINVAL;
+
+       if (vif->sme_state != SME_CONNECTED)
+               return -ENOTCONN;
+
+       ev = (struct wmi_txe_notify_event *) datap;
+       rate = le32_to_cpu(ev->rate);
+       pkts = le32_to_cpu(ev->pkts);
+
+       ath6kl_dbg(ATH6KL_DBG_WMI, "TXE notify event: peer %pM rate %d% pkts %d intvl %ds\n",
+                  vif->bssid, rate, pkts, vif->txe_intvl);
+
+       cfg80211_cqm_txe_notify(vif->ndev, vif->bssid, pkts,
+                               rate, vif->txe_intvl, GFP_KERNEL);
+
+       return 0;
+}
+
+int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
+                             u32 rate, u32 pkts, u32 intvl)
+{
+       struct sk_buff *skb;
+       struct wmi_txe_notify_cmd *cmd;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_txe_notify_cmd *) skb->data;
+       cmd->rate = cpu_to_le32(rate);
+       cmd->pkts = cpu_to_le32(pkts);
+       cmd->intvl = cpu_to_le32(intvl);
+
+       return ath6kl_wmi_cmd_send(wmi, idx, skb, WMI_SET_TXE_NOTIFY_CMDID,
+                                  NO_SYNC_WMIFLAG);
+}
+
+int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi)
+{
+       struct sk_buff *skb;
+       struct wmi_set_rssi_filter_cmd *cmd;
+       int ret;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_set_rssi_filter_cmd *) skb->data;
+       cmd->rssi = rssi;
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_SET_RSSI_FILTER_CMDID,
+                                 NO_SYNC_WMIFLAG);
+       return ret;
+}
+
 static int ath6kl_wmi_send_snr_threshold_params(struct wmi *wmi,
                        struct wmi_snr_threshold_params_cmd *snr_cmd)
 {
@@ -1677,8 +1745,11 @@ int ath6kl_wmi_cmd_send(struct wmi *wmi, u8 if_idx, struct sk_buff *skb,
        int ret;
        u16 info1;
 
-       if (WARN_ON(skb == NULL || (if_idx > (wmi->parent_dev->vif_max - 1))))
+       if (WARN_ON(skb == NULL ||
+                   (if_idx > (wmi->parent_dev->vif_max - 1)))) {
+               dev_kfree_skb(skb);
                return -EINVAL;
+       }
 
        ath6kl_dbg(ATH6KL_DBG_WMI, "wmi tx id %d len %d flag %d\n",
                   cmd_id, skb->len, sync_flag);
@@ -1833,6 +1904,59 @@ int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx)
        return ret;
 }
 
+/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
+ * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
+ * mgmt operations using station interface.
+ */
+static int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
+                                   enum wmi_scan_type scan_type,
+                                   u32 force_fgscan, u32 is_legacy,
+                                   u32 home_dwell_time,
+                                   u32 force_scan_interval,
+                                   s8 num_chan, u16 *ch_list)
+{
+       struct sk_buff *skb;
+       struct wmi_start_scan_cmd *sc;
+       s8 size;
+       int i, ret;
+
+       size = sizeof(struct wmi_start_scan_cmd);
+
+       if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
+               return -EINVAL;
+
+       if (num_chan > WMI_MAX_CHANNELS)
+               return -EINVAL;
+
+       if (num_chan)
+               size += sizeof(u16) * (num_chan - 1);
+
+       skb = ath6kl_wmi_get_new_buf(size);
+       if (!skb)
+               return -ENOMEM;
+
+       sc = (struct wmi_start_scan_cmd *) skb->data;
+       sc->scan_type = scan_type;
+       sc->force_fg_scan = cpu_to_le32(force_fgscan);
+       sc->is_legacy = cpu_to_le32(is_legacy);
+       sc->home_dwell_time = cpu_to_le32(home_dwell_time);
+       sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
+       sc->num_ch = num_chan;
+
+       for (i = 0; i < num_chan; i++)
+               sc->ch_list[i] = cpu_to_le16(ch_list[i]);
+
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID,
+                                 NO_SYNC_WMIFLAG);
+
+       return ret;
+}
+
+/*
+ * beginscan supports (compared to old startscan) P2P mgmt operations using
+ * station interface, send additional information like supported rates to
+ * advertise and xmit rates for probe requests
+ */
 int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
                             enum wmi_scan_type scan_type,
                             u32 force_fgscan, u32 is_legacy,
@@ -1848,6 +1972,15 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
        int num_rates;
        u32 ratemask;
 
+       if (!test_bit(ATH6KL_FW_CAPABILITY_STA_P2PDEV_DUPLEX,
+                     ar->fw_capabilities)) {
+               return ath6kl_wmi_startscan_cmd(wmi, if_idx,
+                                               scan_type, force_fgscan,
+                                               is_legacy, home_dwell_time,
+                                               force_scan_interval,
+                                               num_chan, ch_list);
+       }
+
        size = sizeof(struct wmi_begin_scan_cmd);
 
        if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
@@ -1900,50 +2033,24 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
        return ret;
 }
 
-/* ath6kl_wmi_start_scan_cmd is to be deprecated. Use
- * ath6kl_wmi_begin_scan_cmd instead. The new function supports P2P
- * mgmt operations using station interface.
- */
-int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
-                            enum wmi_scan_type scan_type,
-                            u32 force_fgscan, u32 is_legacy,
-                            u32 home_dwell_time, u32 force_scan_interval,
-                            s8 num_chan, u16 *ch_list)
+int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable)
 {
        struct sk_buff *skb;
-       struct wmi_start_scan_cmd *sc;
-       s8 size;
-       int i, ret;
-
-       size = sizeof(struct wmi_start_scan_cmd);
-
-       if ((scan_type != WMI_LONG_SCAN) && (scan_type != WMI_SHORT_SCAN))
-               return -EINVAL;
-
-       if (num_chan > WMI_MAX_CHANNELS)
-               return -EINVAL;
-
-       if (num_chan)
-               size += sizeof(u16) * (num_chan - 1);
+       struct wmi_enable_sched_scan_cmd *sc;
+       int ret;
 
-       skb = ath6kl_wmi_get_new_buf(size);
+       skb = ath6kl_wmi_get_new_buf(sizeof(*sc));
        if (!skb)
                return -ENOMEM;
 
-       sc = (struct wmi_start_scan_cmd *) skb->data;
-       sc->scan_type = scan_type;
-       sc->force_fg_scan = cpu_to_le32(force_fgscan);
-       sc->is_legacy = cpu_to_le32(is_legacy);
-       sc->home_dwell_time = cpu_to_le32(home_dwell_time);
-       sc->force_scan_intvl = cpu_to_le32(force_scan_interval);
-       sc->num_ch = num_chan;
-
-       for (i = 0; i < num_chan; i++)
-               sc->ch_list[i] = cpu_to_le16(ch_list[i]);
+       ath6kl_dbg(ATH6KL_DBG_WMI, "%s scheduled scan on vif %d\n",
+                  enable ? "enabling" : "disabling", if_idx);
+       sc = (struct wmi_enable_sched_scan_cmd *) skb->data;
+       sc->enable = enable ? 1 : 0;
 
-       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb, WMI_START_SCAN_CMDID,
+       ret = ath6kl_wmi_cmd_send(wmi, if_idx, skb,
+                                 WMI_ENABLE_SCHED_SCAN_CMDID,
                                  NO_SYNC_WMIFLAG);
-
        return ret;
 }
 
@@ -2275,8 +2382,10 @@ static int ath6kl_wmi_data_sync_send(struct wmi *wmi, struct sk_buff *skb,
        struct wmi_data_hdr *data_hdr;
        int ret;
 
-       if (WARN_ON(skb == NULL || ep_id == wmi->ep_id))
+       if (WARN_ON(skb == NULL || ep_id == wmi->ep_id)) {
+               dev_kfree_skb(skb);
                return -EINVAL;
+       }
 
        skb_push(skb, sizeof(struct wmi_data_hdr));
 
@@ -2313,10 +2422,8 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
        spin_unlock_bh(&wmi->lock);
 
        skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
-       if (!skb) {
-               ret = -ENOMEM;
-               goto free_skb;
-       }
+       if (!skb)
+               return -ENOMEM;
 
        cmd = (struct wmi_sync_cmd *) skb->data;
 
@@ -2339,7 +2446,7 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
         * then do not send the Synchronize cmd on the control ep
         */
        if (ret)
-               goto free_skb;
+               goto free_cmd_skb;
 
        /*
         * Send sync cmd followed by sync data messages on all
@@ -2349,15 +2456,12 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
                                  NO_SYNC_WMIFLAG);
 
        if (ret)
-               goto free_skb;
-
-       /* cmd buffer sent, we no longer own it */
-       skb = NULL;
+               goto free_data_skb;
 
        for (index = 0; index < num_pri_streams; index++) {
 
                if (WARN_ON(!data_sync_bufs[index].skb))
-                       break;
+                       goto free_data_skb;
 
                ep_id = ath6kl_ac2_endpoint_id(wmi->parent_dev,
                                               data_sync_bufs[index].
@@ -2366,17 +2470,20 @@ static int ath6kl_wmi_sync_point(struct wmi *wmi, u8 if_idx)
                    ath6kl_wmi_data_sync_send(wmi, data_sync_bufs[index].skb,
                                              ep_id, if_idx);
 
-               if (ret)
-                       break;
-
                data_sync_bufs[index].skb = NULL;
+
+               if (ret)
+                       goto free_data_skb;
        }
 
-free_skb:
+       return 0;
+
+free_cmd_skb:
        /* free up any resources left over (possibly due to an error) */
        if (skb)
                dev_kfree_skb(skb);
 
+free_data_skb:
        for (index = 0; index < num_pri_streams; index++) {
                if (data_sync_bufs[index].skb != NULL) {
                        dev_kfree_skb((struct sk_buff *)data_sync_bufs[index].
@@ -2618,11 +2725,13 @@ static int ath6kl_set_bitrate_mask64(struct wmi *wmi, u8 if_idx,
 {
        struct sk_buff *skb;
        int ret, mode, band;
-       u64 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+       u64 mcsrate, ratemask[ATH6KL_NUM_BANDS];
        struct wmi_set_tx_select_rates64_cmd *cmd;
 
        memset(&ratemask, 0, sizeof(ratemask));
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+
+       /* only check 2.4 and 5 GHz bands, skip the rest */
+       for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {
                /* copy legacy rate mask */
                ratemask[band] = mask->control[band].legacy;
                if (band == IEEE80211_BAND_5GHZ)
@@ -2668,11 +2777,13 @@ static int ath6kl_set_bitrate_mask32(struct wmi *wmi, u8 if_idx,
 {
        struct sk_buff *skb;
        int ret, mode, band;
-       u32 mcsrate, ratemask[IEEE80211_NUM_BANDS];
+       u32 mcsrate, ratemask[ATH6KL_NUM_BANDS];
        struct wmi_set_tx_select_rates32_cmd *cmd;
 
        memset(&ratemask, 0, sizeof(ratemask));
-       for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
+
+       /* only check 2.4 and 5 GHz bands, skip the rest */
+       for (band = 0; band <= IEEE80211_BAND_5GHZ; band++) {
                /* copy legacy rate mask */
                ratemask[band] = mask->control[band].legacy;
                if (band == IEEE80211_BAND_5GHZ)
@@ -2716,7 +2827,7 @@ int ath6kl_wmi_set_bitrate_mask(struct wmi *wmi, u8 if_idx,
 {
        struct ath6kl *ar = wmi->parent_dev;
 
-       if (ar->hw.flags & ATH6KL_HW_FLAG_64BIT_RATES)
+       if (ar->hw.flags & ATH6KL_HW_64BIT_RATES)
                return ath6kl_set_bitrate_mask64(wmi, if_idx, mask);
        else
                return ath6kl_set_bitrate_mask32(wmi, if_idx, mask);
@@ -3139,12 +3250,40 @@ int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enhance)
        return ret;
 }
 
+int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2)
+{
+       struct sk_buff *skb;
+       struct wmi_set_regdomain_cmd *cmd;
+
+       skb = ath6kl_wmi_get_new_buf(sizeof(*cmd));
+       if (!skb)
+               return -ENOMEM;
+
+       cmd = (struct wmi_set_regdomain_cmd *) skb->data;
+       memcpy(cmd->iso_name, alpha2, 2);
+
+       return ath6kl_wmi_cmd_send(wmi, 0, skb,
+                                  WMI_SET_REGDOMAIN_CMDID,
+                                  NO_SYNC_WMIFLAG);
+}
+
 s32 ath6kl_wmi_get_rate(s8 rate_index)
 {
+       u8 sgi = 0;
+
        if (rate_index == RATE_AUTO)
                return 0;
 
-       return wmi_rate_tbl[(u32) rate_index][0];
+       /* SGI is stored as the MSB of the rate_index */
+       if (rate_index & RATE_INDEX_MSB) {
+               rate_index &= RATE_INDEX_WITHOUT_SGI_MASK;
+               sgi = 1;
+       }
+
+       if (WARN_ON(rate_index > RATE_MCS_7_40))
+               rate_index = RATE_MCS_7_40;
+
+       return wmi_rate_tbl[(u32) rate_index][sgi];
 }
 
 static int ath6kl_wmi_get_pmkid_list_event_rx(struct wmi *wmi, u8 *datap,
@@ -3634,6 +3773,19 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout)
                                   NO_SYNC_WMIFLAG);
 }
 
+static void ath6kl_wmi_hb_challenge_resp_event(struct wmi *wmi, u8 *datap,
+                                              int len)
+{
+       struct wmix_hb_challenge_resp_cmd *cmd;
+
+       if (len < sizeof(struct wmix_hb_challenge_resp_cmd))
+               return;
+
+       cmd = (struct wmix_hb_challenge_resp_cmd *) datap;
+       ath6kl_recovery_hb_event(wmi->parent_dev,
+                                le32_to_cpu(cmd->cookie));
+}
+
 static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
 {
        struct wmix_cmd_hdr *cmd;
@@ -3658,6 +3810,7 @@ static int ath6kl_wmi_control_rx_xtnd(struct wmi *wmi, struct sk_buff *skb)
        switch (id) {
        case WMIX_HB_CHALLENGE_RESP_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event hb challenge resp\n");
+               ath6kl_wmi_hb_challenge_resp_event(wmi, datap, len);
                break;
        case WMIX_DBGLOG_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "wmi event dbglog len %d\n", len);
@@ -3750,6 +3903,9 @@ static int ath6kl_wmi_proc_events_vif(struct wmi *wmi, u16 if_idx, u16 cmd_id,
        case WMI_RX_ACTION_EVENTID:
                ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_RX_ACTION_EVENTID\n");
                return ath6kl_wmi_rx_action_event_rx(wmi, datap, len, vif);
+       case WMI_TXE_NOTIFY_EVENTID:
+               ath6kl_dbg(ATH6KL_DBG_WMI, "WMI_TXE_NOTIFY_EVENTID\n");
+               return ath6kl_wmi_txe_notify_event_rx(wmi, datap, len, vif);
        default:
                ath6kl_dbg(ATH6KL_DBG_WMI, "unknown cmd id 0x%x\n", cmd_id);
                return -EINVAL;
index 43339aca585d96508cc9d2b7f87b4cf743cca3c9..98b1755e67f41f41f2af6f06ff6747731572aaca 100644 (file)
@@ -48,7 +48,7 @@
 
 #define A_BAND_24GHZ           0
 #define A_BAND_5GHZ            1
-#define A_NUM_BANDS            2
+#define ATH6KL_NUM_BANDS       2
 
 /* in ms */
 #define WMI_IMPLICIT_PSTREAM_INACTIVITY_INT 5000
@@ -628,6 +628,20 @@ enum wmi_cmd_id {
        WMI_SET_MCASTRATE,
 
        WMI_STA_BMISS_ENHANCE_CMDID,
+
+       WMI_SET_REGDOMAIN_CMDID,
+
+       WMI_SET_RSSI_FILTER_CMDID,
+
+       WMI_SET_KEEP_ALIVE_EXT,
+
+       WMI_VOICE_DETECTION_ENABLE_CMDID,
+
+       WMI_SET_TXE_NOTIFY_CMDID,
+
+       WMI_SET_RECOVERY_TEST_PARAMETER_CMDID, /*0xf094*/
+
+       WMI_ENABLE_SCHED_SCAN_CMDID,
 };
 
 enum wmi_mgmt_frame_type {
@@ -843,7 +857,7 @@ struct wmi_begin_scan_cmd {
        u8 scan_type;
 
        /* Supported rates to advertise in the probe request frames */
-       struct wmi_supp_rates supp_rates[IEEE80211_NUM_BANDS];
+       struct wmi_supp_rates supp_rates[ATH6KL_NUM_BANDS];
 
        /* how many channels follow */
        u8 num_ch;
@@ -941,6 +955,11 @@ struct wmi_scan_params_cmd {
        __le32 max_dfsch_act_time;
 } __packed;
 
+/* WMI_ENABLE_SCHED_SCAN_CMDID */
+struct wmi_enable_sched_scan_cmd {
+       u8 enable;
+} __packed;
+
 /* WMI_SET_BSS_FILTER_CMDID */
 enum wmi_bss_filter {
        /* no beacons forwarded */
@@ -1032,6 +1051,11 @@ struct wmi_sta_bmiss_enhance_cmd {
        u8 enable;
 } __packed;
 
+struct wmi_set_regdomain_cmd {
+       u8 length;
+       u8 iso_name[2];
+} __packed;
+
 /* WMI_SET_POWER_MODE_CMDID */
 enum wmi_power_mode {
        REC_POWER = 0x01,
@@ -1276,6 +1300,11 @@ struct wmi_snr_threshold_params_cmd {
        u8 reserved[3];
 } __packed;
 
+/* Don't report BSSs with signal (RSSI) below this threshold */
+struct wmi_set_rssi_filter_cmd {
+       s8 rssi;
+} __packed;
+
 enum wmi_preamble_policy {
        WMI_IGNORE_BARKER_IN_ERP = 0,
        WMI_FOLLOW_BARKER_IN_ERP,
@@ -1455,6 +1484,20 @@ enum wmi_event_id {
        WMI_P2P_CAPABILITIES_EVENTID,
        WMI_RX_ACTION_EVENTID,
        WMI_P2P_INFO_EVENTID,
+
+       /* WPS Events */
+       WMI_WPS_GET_STATUS_EVENTID,
+       WMI_WPS_PROFILE_EVENTID,
+
+       /* more P2P events */
+       WMI_NOA_INFO_EVENTID,
+       WMI_OPPPS_INFO_EVENTID,
+       WMI_PORT_STATUS_EVENTID,
+
+       /* 802.11w */
+       WMI_GET_RSN_CAP_EVENTID,
+
+       WMI_TXE_NOTIFY_EVENTID,
 };
 
 struct wmi_ready_event_2 {
@@ -1749,6 +1792,9 @@ struct rx_stats {
        a_sle32 ucast_rate;
 } __packed;
 
+#define RATE_INDEX_WITHOUT_SGI_MASK     0x7f
+#define RATE_INDEX_MSB     0x80
+
 struct tkip_ccmp_stats {
        __le32 tkip_local_mic_fail;
        __le32 tkip_cnter_measures_invoked;
@@ -2019,7 +2065,6 @@ struct wmi_set_ie_cmd {
 
 #define WOW_MAX_FILTERS_PER_LIST 4
 #define WOW_PATTERN_SIZE        64
-#define WOW_MASK_SIZE           64
 
 #define MAC_MAX_FILTERS_PER_LIST 4
 
@@ -2028,7 +2073,7 @@ struct wow_filter {
        u8 wow_filter_id;
        u8 wow_filter_size;
        u8 wow_filter_offset;
-       u8 wow_filter_mask[WOW_MASK_SIZE];
+       u8 wow_filter_mask[WOW_PATTERN_SIZE];
        u8 wow_filter_pattern[WOW_PATTERN_SIZE];
 } __packed;
 
@@ -2087,6 +2132,19 @@ struct wmi_del_wow_pattern_cmd {
        __le16 filter_id;
 } __packed;
 
+/* WMI_SET_TXE_NOTIFY_CMDID */
+struct wmi_txe_notify_cmd {
+       __le32 rate;
+       __le32 pkts;
+       __le32 intvl;
+} __packed;
+
+/* WMI_TXE_NOTIFY_EVENTID */
+struct wmi_txe_notify_event {
+       __le32 rate;
+       __le32 pkts;
+} __packed;
+
 /* WMI_SET_AKMP_PARAMS_CMD */
 
 struct wmi_pmkid {
@@ -2505,11 +2563,6 @@ int ath6kl_wmi_connect_cmd(struct wmi *wmi, u8 if_idx,
 int ath6kl_wmi_reconnect_cmd(struct wmi *wmi, u8 if_idx, u8 *bssid,
                             u16 channel);
 int ath6kl_wmi_disconnect_cmd(struct wmi *wmi, u8 if_idx);
-int ath6kl_wmi_startscan_cmd(struct wmi *wmi, u8 if_idx,
-                            enum wmi_scan_type scan_type,
-                            u32 force_fgscan, u32 is_legacy,
-                            u32 home_dwell_time, u32 force_scan_interval,
-                            s8 num_chan, u16 *ch_list);
 
 int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
                             enum wmi_scan_type scan_type,
@@ -2517,6 +2570,7 @@ int ath6kl_wmi_beginscan_cmd(struct wmi *wmi, u8 if_idx,
                             u32 home_dwell_time, u32 force_scan_interval,
                             s8 num_chan, u16 *ch_list, u32 no_cck,
                             u32 *rates);
+int ath6kl_wmi_enable_sched_scan_cmd(struct wmi *wmi, u8 if_idx, bool enable);
 
 int ath6kl_wmi_scanparams_cmd(struct wmi *wmi, u8 if_idx, u16 fg_start_sec,
                              u16 fg_end_sec, u16 bg_sec,
@@ -2592,6 +2646,7 @@ int ath6kl_wmi_add_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
                                   const u8 *mask);
 int ath6kl_wmi_del_wow_pattern_cmd(struct wmi *wmi, u8 if_idx,
                                   u16 list_id, u16 filter_id);
+int ath6kl_wmi_set_rssi_filter_cmd(struct wmi *wmi, u8 if_idx, s8 rssi);
 int ath6kl_wmi_set_roam_lrssi_cmd(struct wmi *wmi, u8 lrssi);
 int ath6kl_wmi_ap_set_dtim_cmd(struct wmi *wmi, u8 if_idx, u32 dtim_period);
 int ath6kl_wmi_force_roam_cmd(struct wmi *wmi, const u8 *bssid);
@@ -2600,6 +2655,9 @@ int ath6kl_wmi_mcast_filter_cmd(struct wmi *wmi, u8 if_idx, bool mc_all_on);
 int ath6kl_wmi_add_del_mcast_filter_cmd(struct wmi *wmi, u8 if_idx,
                                        u8 *filter, bool add_filter);
 int ath6kl_wmi_sta_bmiss_enhance_cmd(struct wmi *wmi, u8 if_idx, bool enable);
+int ath6kl_wmi_set_txe_notify(struct wmi *wmi, u8 idx,
+                             u32 rate, u32 pkts, u32 intvl);
+int ath6kl_wmi_set_regdomain_cmd(struct wmi *wmi, const char *alpha2);
 
 /* AP mode uAPSD */
 int ath6kl_wmi_ap_set_apsd(struct wmi *wmi, u8 if_idx, u8 enable);
@@ -2658,6 +2716,8 @@ int ath6kl_wmi_set_inact_period(struct wmi *wmi, u8 if_idx, int inact_timeout);
 
 void ath6kl_wmi_sscan_timer(unsigned long ptr);
 
+int ath6kl_wmi_get_challenge_resp_cmd(struct wmi *wmi, u32 cookie, u32 source);
+
 struct ath6kl_vif *ath6kl_get_vif_by_index(struct ath6kl *ar, u8 if_idx);
 void *ath6kl_wmi_init(struct ath6kl *devt);
 void ath6kl_wmi_shutdown(struct wmi *wmi);
index 162401f22f8cd96d326485a56a81e4d52e7f30d4..8b0d8dcd76255239e7451b4a1258adca79ef8342 100644 (file)
@@ -891,6 +891,74 @@ static void ar9003_hw_tx_iq_cal_reload(struct ath_hw *ah)
                      AR_PHY_RX_IQCAL_CORR_B0_LOOPBACK_IQCORR_EN, 0x1);
 }
 
+static void ar9003_hw_manual_peak_cal(struct ath_hw *ah, u8 chain, bool is_2g)
+{
+       int offset[8], total = 0, test;
+       int agc_out, i;
+
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
+                     AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
+                     AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC, 0x0);
+       if (is_2g)
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
+                             AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR, 0x0);
+       else
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
+                             AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR, 0x0);
+
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
+                     AR_PHY_65NM_RXTX2_RXON_OVR, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
+                     AR_PHY_65NM_RXTX2_RXON, 0x0);
+
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                     AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                     AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR, 0x1);
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                     AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0x1);
+       if (is_2g)
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                             AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR, 0x0);
+       else
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                             AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR, 0x0);
+
+       for (i = 6; i > 0; i--) {
+               offset[i] = BIT(i - 1);
+               test = total + offset[i];
+
+               if (is_2g)
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                                     AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR,
+                                     test);
+               else
+                       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                                     AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR,
+                                     test);
+               udelay(100);
+               agc_out = REG_READ_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                                        AR_PHY_65NM_RXRF_AGC_AGC_OUT);
+               offset[i] = (agc_out) ? 0 : 1;
+               total += (offset[i] << (i - 1));
+       }
+
+       if (is_2g)
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                             AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR, total);
+       else
+               REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                             AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR, total);
+
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_GAINSTAGES(chain),
+                     AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE, 0);
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXTX2(chain),
+                     AR_PHY_65NM_RXTX2_RXON_OVR, 0);
+       REG_RMW_FIELD(ah, AR_PHY_65NM_RXRF_AGC(chain),
+                     AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR, 0);
+}
+
 static bool ar9003_hw_init_cal(struct ath_hw *ah,
                               struct ath9k_channel *chan)
 {
@@ -989,6 +1057,14 @@ skip_tx_iqcal:
                status = ath9k_hw_wait(ah, AR_PHY_AGC_CONTROL,
                                       AR_PHY_AGC_CONTROL_CAL,
                                       0, AH_WAIT_TIMEOUT);
+               if (AR_SREV_9462(ah) || AR_SREV_9565(ah)) {
+                       for (i = 0; i < AR9300_MAX_CHAINS; i++) {
+                               if (!(ah->rxchainmask & (1 << i)))
+                                       continue;
+                               ar9003_hw_manual_peak_cal(ah, i,
+                                                         IS_CHAN_2GHZ(chan));
+                       }
+               }
        }
 
        if (ath9k_hw_mci_is_enabled(ah) && IS_CHAN_2GHZ(chan) && run_agc_cal)
index 0693cd95b746298e841e10980584ef9ce3de386d..74fd3977feeb845adf93f6ed0fd650d506ca2ee1 100644 (file)
  */
 static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
 {
-#define AR9462_BB_CTX_COEFJ(x) \
-               ar9462_##x##_baseband_core_txfir_coeff_japan_2484
-
-#define AR9462_BBC_TXIFR_COEFFJ \
-               ar9462_2p0_baseband_core_txfir_coeff_japan_2484
-
        if (AR_SREV_9330_11(ah)) {
                /* mac */
                INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
@@ -70,6 +64,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                                ar9331_modes_lowest_ob_db_tx_gain_1p1);
 
+               /* Japan 2484 Mhz CCK */
+               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+                              ar9331_1p1_baseband_core_txfir_coeff_japan_2484);
+
                /* additional clock settings */
                if (ah->is_clk_25mhz)
                        INIT_INI_ARRAY(&ah->iniAdditional,
@@ -106,6 +104,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                                ar9331_modes_lowest_ob_db_tx_gain_1p2);
 
+               /* Japan 2484 Mhz CCK */
+               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+                              ar9331_1p2_baseband_core_txfir_coeff_japan_2484);
+
                /* additional clock settings */
                if (ah->is_clk_25mhz)
                        INIT_INI_ARRAY(&ah->iniAdditional,
@@ -180,6 +182,10 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                INIT_INI_ARRAY(&ah->iniModesTxGain,
                                ar9485_modes_lowest_ob_db_tx_gain_1_1);
 
+               /* Japan 2484 Mhz CCK */
+               INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
+                              ar9485_1_1_baseband_core_txfir_coeff_japan_2484);
+
                /* Load PCIE SERDES settings from INI */
 
                /* Awake Setting */
@@ -229,9 +235,7 @@ static void ar9003_hw_init_mode_regs(struct ath_hw *ah)
                                ar9462_modes_fast_clock_2p0);
 
                INIT_INI_ARRAY(&ah->iniCckfirJapan2484,
-                               AR9462_BB_CTX_COEFJ(2p0));
-
-               INIT_INI_ARRAY(&ah->ini_japan2484, AR9462_BBC_TXIFR_COEFFJ);
+                              ar9462_2p0_baseband_core_txfir_coeff_japan_2484);
        } else if (AR_SREV_9550(ah)) {
                /* mac */
                INIT_INI_ARRAY(&ah->iniMac[ATH_INI_CORE],
index 42b4412d6794b3b141acf37cdb99709d4491404f..8dd069259e7b7ea7d9dd40212571cab73424f131 100644 (file)
@@ -714,7 +714,6 @@ bool ar9003_mci_start_reset(struct ath_hw *ah, struct ath9k_channel *chan)
 
        return true;
 }
-EXPORT_SYMBOL(ar9003_mci_start_reset);
 
 int ar9003_mci_end_reset(struct ath_hw *ah, struct ath9k_channel *chan,
                         struct ath9k_hw_cal_data *caldata)
index 759f5f5a715469bb43c054b45d4d8ed5f6917302..ce19c09fa8e84aec2877e2f14861b0284f4d958e 100644 (file)
@@ -784,7 +784,7 @@ static int ar9003_hw_process_ini(struct ath_hw *ah,
        REG_WRITE_ARRAY(&ah->iniAdditional, 1, regWrites);
 
        if (chan->channel == 2484)
-               ar9003_hw_prog_ini(ah, &ah->ini_japan2484, 1);
+               ar9003_hw_prog_ini(ah, &ah->iniCckfirJapan2484, 1);
 
        if (AR_SREV_9462(ah) || AR_SREV_9565(ah))
                REG_WRITE(ah, AR_GLB_SWREG_DISCONT_MODE,
index 8f585233a788179e5dfe7ddbe7ea5fa654d68eec..4c3d06de7111d75e18e46c0fc9d2b5412f3e37ad 100644 (file)
 #define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT   0x0000ff00
 #define AR_PHY_65NM_CH0_THERM_SAR_ADC_OUT_S 8
 
-#define AR_PHY_65NM_CH0_RXTX1       0x16100
-#define AR_PHY_65NM_CH0_RXTX2       0x16104
-#define AR_PHY_65NM_CH1_RXTX1       0x16500
-#define AR_PHY_65NM_CH1_RXTX2       0x16504
-#define AR_PHY_65NM_CH2_RXTX1       0x16900
-#define AR_PHY_65NM_CH2_RXTX2       0x16904
-
 #define AR_CH0_TOP2            (AR_SREV_9300(ah) ? 0x1628c : \
                                        (AR_SREV_9462(ah) ? 0x16290 : 0x16284))
 #define AR_CH0_TOP2_XPABIASLVL         0xf000
 #define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD          0xFC000000
 #define AR_BTCOEX_WL_LNADIV_BT_INACTIVE_THRESHOLD_S        26
 
+/* Manual Peak detector calibration */
+#define AR_PHY_65NM_BASE                               0x16000
+#define AR_PHY_65NM_RXRF_GAINSTAGES(i)                 (AR_PHY_65NM_BASE + \
+                                                       (i * 0x400) + 0x8)
+#define AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE        0x80000000
+#define AR_PHY_65NM_RXRF_GAINSTAGES_RX_OVERRIDE_S      31
+#define AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC        0x00000002
+#define AR_PHY_65NM_RXRF_GAINSTAGES_LNAON_CALDC_S      1
+#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR     0x70000000
+#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA2G_GAIN_OVR_S   28
+#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR     0x03800000
+#define AR_PHY_65NM_RXRF_GAINSTAGES_LNA5G_GAIN_OVR_S   23
+
+#define AR_PHY_65NM_RXTX2(i)                           (AR_PHY_65NM_BASE + \
+                                                       (i * 0x400) + 0x104)
+#define AR_PHY_65NM_RXTX2_RXON_OVR                     0x00001000
+#define AR_PHY_65NM_RXTX2_RXON_OVR_S                   12
+#define AR_PHY_65NM_RXTX2_RXON                         0x00000800
+#define AR_PHY_65NM_RXTX2_RXON_S                       11
+
+#define AR_PHY_65NM_RXRF_AGC(i)                        (AR_PHY_65NM_BASE + \
+                                                       (i * 0x400) + 0xc)
+#define AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE              0x80000000
+#define AR_PHY_65NM_RXRF_AGC_AGC_OVERRIDE_S            31
+#define AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR                0x40000000
+#define AR_PHY_65NM_RXRF_AGC_AGC_ON_OVR_S              30
+#define AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR               0x20000000
+#define AR_PHY_65NM_RXRF_AGC_AGC_CAL_OVR_S             29
+#define AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR           0x1E000000
+#define AR_PHY_65NM_RXRF_AGC_AGC2G_DBDAC_OVR_S         25
+#define AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR           0x00078000
+#define AR_PHY_65NM_RXRF_AGC_AGC5G_DBDAC_OVR_S         15
+#define AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR          0x01F80000
+#define AR_PHY_65NM_RXRF_AGC_AGC2G_CALDAC_OVR_S        19
+#define AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR          0x00007e00
+#define AR_PHY_65NM_RXRF_AGC_AGC5G_CALDAC_OVR_S        9
+#define AR_PHY_65NM_RXRF_AGC_AGC_OUT                   0x00000004
+#define AR_PHY_65NM_RXRF_AGC_AGC_OUT_S                 2
+
 #endif  /* AR9003_PHY_H */
index 58f30f65c6b62fa21acb46f2468f171cc7736125..ccc42a71b43642f668aae77158c697e66af85896 100644 (file)
@@ -78,7 +78,7 @@ static const u32 ar9462_2p0_baseband_postamble[][5] = {
        {0x0000a284, 0x00000000, 0x00000000, 0x00000150, 0x00000150},
        {0x0000a288, 0x00000110, 0x00000110, 0x00000110, 0x00000110},
        {0x0000a28c, 0x00022222, 0x00022222, 0x00022222, 0x00022222},
-       {0x0000a2c4, 0x00158d18, 0x00158d18, 0x00158d18, 0x00158d18},
+       {0x0000a2c4, 0x00058d18, 0x00058d18, 0x00058d18, 0x00058d18},
        {0x0000a2d0, 0x00041981, 0x00041981, 0x00041981, 0x00041982},
        {0x0000a2d8, 0x7999a83b, 0x7999a83b, 0x7999a83b, 0x7999a83b},
        {0x0000a358, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
index fb4497fc7a3da1e87547cda3e8a7fe76497504c8..a3710f3bb90c5b0fe8a02cc26455ec31b3697162 100644 (file)
@@ -18,7 +18,7 @@
 #ifndef INITVALS_9485_H
 #define INITVALS_9485_H
 
-/* AR9485 1.0 */
+/* AR9485 1.1 */
 
 #define ar9485_1_1_mac_postamble ar9300_2p2_mac_postamble
 
@@ -31,6 +31,11 @@ static const u32 ar9485_1_1_pcie_phy_pll_on_clkreq_disable_L1[][2] = {
 
 static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
        /* Addr      allmodes  */
+       {0x00009e00, 0x037216a0},
+       {0x00009e04, 0x00182020},
+       {0x00009e18, 0x00000000},
+       {0x00009e2c, 0x00004121},
+       {0x00009e44, 0x02282324},
        {0x0000a000, 0x00060005},
        {0x0000a004, 0x00810080},
        {0x0000a008, 0x00830082},
@@ -164,6 +169,11 @@ static const u32 ar9485Common_wo_xlna_rx_gain_1_1[][2] = {
 static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
        /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
        {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
+       {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
        {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
        {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
@@ -198,6 +208,22 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
        {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
        {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
        {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501},
+       {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803},
+       {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04},
+       {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
        {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
        {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
@@ -234,9 +260,193 @@ static const u32 ar9485Modes_high_power_tx_gain_1_1[][5] = {
        {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
 };
 
-#define ar9485Modes_high_ob_db_tx_gain_1_1 ar9485Modes_high_power_tx_gain_1_1
+static const u32 ar9485Modes_high_ob_db_tx_gain_1_1[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
+       {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e0, 0x00000000, 0x00000000, 0xffc63a84, 0xffc63a84},
+       {0x0000a2e4, 0x00000000, 0x00000000, 0xfe0fc000, 0xfe0fc000},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0xfff00000, 0xfff00000},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+       {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+       {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+       {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+       {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
+       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
+       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+       {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+       {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501},
+       {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803},
+       {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04},
+       {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+       {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
 
-#define ar9485Modes_low_ob_db_tx_gain_1_1 ar9485Modes_high_ob_db_tx_gain_1_1
+static const u32 ar9485Modes_low_ob_db_tx_gain_1_1[][5] = {
+       /* Addr      5G_HT20     5G_HT40     2G_HT40     2G_HT20   */
+       {0x000098bc, 0x00000002, 0x00000002, 0x00000002, 0x00000002},
+       {0x0000a2d8, 0xf999a83a, 0xf999a83a, 0x7999a83a, 0x7999a83a},
+       {0x0000a2dc, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e0, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e4, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a2e8, 0x00000000, 0x00000000, 0xfe2d3552, 0xfe2d3552},
+       {0x0000a410, 0x000050d9, 0x000050d9, 0x000050d8, 0x000050d8},
+       {0x0000a458, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a500, 0x00022200, 0x00022200, 0x00000000, 0x00000000},
+       {0x0000a504, 0x05062002, 0x05062002, 0x04000002, 0x04000002},
+       {0x0000a508, 0x0c002e00, 0x0c002e00, 0x08000004, 0x08000004},
+       {0x0000a50c, 0x11062202, 0x11062202, 0x0d000200, 0x0d000200},
+       {0x0000a510, 0x17022e00, 0x17022e00, 0x11000202, 0x11000202},
+       {0x0000a514, 0x1d000ec2, 0x1d000ec2, 0x15000400, 0x15000400},
+       {0x0000a518, 0x25020ec0, 0x25020ec0, 0x19000402, 0x19000402},
+       {0x0000a51c, 0x2b020ec3, 0x2b020ec3, 0x1d000404, 0x1d000404},
+       {0x0000a520, 0x2f001f04, 0x2f001f04, 0x21000603, 0x21000603},
+       {0x0000a524, 0x35001fc4, 0x35001fc4, 0x25000605, 0x25000605},
+       {0x0000a528, 0x3c022f04, 0x3c022f04, 0x2a000a03, 0x2a000a03},
+       {0x0000a52c, 0x41023e85, 0x41023e85, 0x2c000a04, 0x2c000a04},
+       {0x0000a530, 0x48023ec6, 0x48023ec6, 0x34000e20, 0x34000e20},
+       {0x0000a534, 0x4d023f01, 0x4d023f01, 0x35000e21, 0x35000e21},
+       {0x0000a538, 0x53023f4b, 0x53023f4b, 0x43000e62, 0x43000e62},
+       {0x0000a53c, 0x5a027f09, 0x5a027f09, 0x45000e63, 0x45000e63},
+       {0x0000a540, 0x5f027fc9, 0x5f027fc9, 0x49000e65, 0x49000e65},
+       {0x0000a544, 0x6502feca, 0x6502feca, 0x4b000e66, 0x4b000e66},
+       {0x0000a548, 0x6b02ff4a, 0x6b02ff4a, 0x4d001645, 0x4d001645},
+       {0x0000a54c, 0x7203feca, 0x7203feca, 0x51001865, 0x51001865},
+       {0x0000a550, 0x7703ff0b, 0x7703ff0b, 0x55001a86, 0x55001a86},
+       {0x0000a554, 0x7d06ffcb, 0x7d06ffcb, 0x57001ce9, 0x57001ce9},
+       {0x0000a558, 0x8407ff0b, 0x8407ff0b, 0x5a001ceb, 0x5a001ceb},
+       {0x0000a55c, 0x8907ffcb, 0x8907ffcb, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a560, 0x900fff0b, 0x900fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a564, 0x960fffcb, 0x960fffcb, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a568, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a56c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a570, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a574, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a578, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a57c, 0x9c1fff0b, 0x9c1fff0b, 0x5e001eeb, 0x5e001eeb},
+       {0x0000a580, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a584, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a588, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a58c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a590, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a594, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000a598, 0x00000000, 0x00000000, 0x01404501, 0x01404501},
+       {0x0000a59c, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a0, 0x00000000, 0x00000000, 0x02808a02, 0x02808a02},
+       {0x0000a5a4, 0x00000000, 0x00000000, 0x02808803, 0x02808803},
+       {0x0000a5a8, 0x00000000, 0x00000000, 0x04c14b04, 0x04c14b04},
+       {0x0000a5ac, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b0, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b4, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5b8, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000a5bc, 0x00000000, 0x00000000, 0x04c15305, 0x04c15305},
+       {0x0000b500, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b504, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b508, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b50c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b510, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b514, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b518, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b51c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b520, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b524, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b528, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b52c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b530, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b534, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b538, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b53c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b540, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b544, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b548, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b54c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b550, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b554, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b558, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b55c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b560, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b564, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b568, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b56c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b570, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b574, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b578, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x0000b57c, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00016044, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db, 0x05d6b2db},
+       {0x00016048, 0x6c924260, 0x6c924260, 0x6c924260, 0x6c924260},
+};
 
 #define ar9485_modes_lowest_ob_db_tx_gain_1_1 ar9485Modes_low_ob_db_tx_gain_1_1
 
@@ -245,19 +455,19 @@ static const u32 ar9485_1_1[][2] = {
        {0x0000a580, 0x00000000},
        {0x0000a584, 0x00000000},
        {0x0000a588, 0x00000000},
-       {0x0000a58c, 0x00000000},
-       {0x0000a590, 0x00000000},
-       {0x0000a594, 0x00000000},
-       {0x0000a598, 0x00000000},
-       {0x0000a59c, 0x00000000},
-       {0x0000a5a0, 0x00000000},
-       {0x0000a5a4, 0x00000000},
-       {0x0000a5a8, 0x00000000},
-       {0x0000a5ac, 0x00000000},
-       {0x0000a5b0, 0x00000000},
-       {0x0000a5b4, 0x00000000},
-       {0x0000a5b8, 0x00000000},
-       {0x0000a5bc, 0x00000000},
+       {0x0000a58c, 0x01804000},
+       {0x0000a590, 0x02808a02},
+       {0x0000a594, 0x0340ca02},
+       {0x0000a598, 0x0340cd03},
+       {0x0000a59c, 0x0340cd03},
+       {0x0000a5a0, 0x06415304},
+       {0x0000a5a4, 0x04c11905},
+       {0x0000a5a8, 0x06415905},
+       {0x0000a5ac, 0x06415905},
+       {0x0000a5b0, 0x06415905},
+       {0x0000a5b4, 0x06415905},
+       {0x0000a5b8, 0x06415905},
+       {0x0000a5bc, 0x06415905},
 };
 
 static const u32 ar9485_1_1_radio_core[][2] = {
@@ -340,7 +550,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
        {0x00009880, 0x201fff00},
        {0x00009884, 0x00001042},
        {0x000098a4, 0x00200400},
-       {0x000098b0, 0x52440bbe},
+       {0x000098b0, 0x32840bbe},
        {0x000098d0, 0x004b6a8e},
        {0x000098d4, 0x00000820},
        {0x000098dc, 0x00000000},
@@ -362,7 +572,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
        {0x00009d18, 0x00000000},
        {0x00009d1c, 0x00000000},
        {0x00009e08, 0x0038233c},
-       {0x00009e24, 0x9927b515},
+       {0x00009e24, 0x992bb515},
        {0x00009e28, 0x12ef0200},
        {0x00009e30, 0x06336f77},
        {0x00009e34, 0x6af6532f},
@@ -427,7 +637,7 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
        {0x0000a408, 0x0e79e5c6},
        {0x0000a40c, 0x00820820},
        {0x0000a414, 0x1ce739cf},
-       {0x0000a418, 0x2d0019ce},
+       {0x0000a418, 0x2d0021ce},
        {0x0000a41c, 0x1ce739ce},
        {0x0000a420, 0x000001ce},
        {0x0000a424, 0x1ce739ce},
@@ -443,8 +653,8 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
        {0x0000a44c, 0x00000001},
        {0x0000a450, 0x00010000},
        {0x0000a5c4, 0xbfad9d74},
-       {0x0000a5c8, 0x0048060a},
-       {0x0000a5cc, 0x00000637},
+       {0x0000a5c8, 0x00480605},
+       {0x0000a5cc, 0x00002e37},
        {0x0000a760, 0x03020100},
        {0x0000a764, 0x09080504},
        {0x0000a768, 0x0d0c0b0a},
@@ -464,17 +674,22 @@ static const u32 ar9485_1_1_baseband_core[][2] = {
 
 static const u32 ar9485_common_rx_gain_1_1[][2] = {
        /* Addr      allmodes  */
-       {0x0000a000, 0x00010000},
-       {0x0000a004, 0x00030002},
-       {0x0000a008, 0x00050004},
-       {0x0000a00c, 0x00810080},
-       {0x0000a010, 0x01800082},
-       {0x0000a014, 0x01820181},
-       {0x0000a018, 0x01840183},
-       {0x0000a01c, 0x01880185},
-       {0x0000a020, 0x018a0189},
-       {0x0000a024, 0x02850284},
-       {0x0000a028, 0x02890288},
+       {0x00009e00, 0x03721b20},
+       {0x00009e04, 0x00082020},
+       {0x00009e18, 0x0300501e},
+       {0x00009e2c, 0x00002e21},
+       {0x00009e44, 0x02182324},
+       {0x0000a000, 0x00060005},
+       {0x0000a004, 0x00810080},
+       {0x0000a008, 0x00830082},
+       {0x0000a00c, 0x00850084},
+       {0x0000a010, 0x01820181},
+       {0x0000a014, 0x01840183},
+       {0x0000a018, 0x01880185},
+       {0x0000a01c, 0x018a0189},
+       {0x0000a020, 0x02850284},
+       {0x0000a024, 0x02890288},
+       {0x0000a028, 0x028b028a},
        {0x0000a02c, 0x03850384},
        {0x0000a030, 0x03890388},
        {0x0000a034, 0x038b038a},
@@ -496,15 +711,15 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = {
        {0x0000a074, 0x00000000},
        {0x0000a078, 0x00000000},
        {0x0000a07c, 0x00000000},
-       {0x0000a080, 0x28282828},
-       {0x0000a084, 0x28282828},
-       {0x0000a088, 0x28282828},
-       {0x0000a08c, 0x28282828},
-       {0x0000a090, 0x28282828},
-       {0x0000a094, 0x21212128},
-       {0x0000a098, 0x171c1c1c},
-       {0x0000a09c, 0x02020212},
-       {0x0000a0a0, 0x00000202},
+       {0x0000a080, 0x18181818},
+       {0x0000a084, 0x18181818},
+       {0x0000a088, 0x18181818},
+       {0x0000a08c, 0x18181818},
+       {0x0000a090, 0x18181818},
+       {0x0000a094, 0x18181818},
+       {0x0000a098, 0x17181818},
+       {0x0000a09c, 0x02020b0b},
+       {0x0000a0a0, 0x02020202},
        {0x0000a0a4, 0x00000000},
        {0x0000a0a8, 0x00000000},
        {0x0000a0ac, 0x00000000},
@@ -512,22 +727,22 @@ static const u32 ar9485_common_rx_gain_1_1[][2] = {
        {0x0000a0b4, 0x00000000},
        {0x0000a0b8, 0x00000000},
        {0x0000a0bc, 0x00000000},
-       {0x0000a0c0, 0x001f0000},
-       {0x0000a0c4, 0x111f1100},
-       {0x0000a0c8, 0x111d111e},
-       {0x0000a0cc, 0x111b111c},
-       {0x0000a0d0, 0x22032204},
-       {0x0000a0d4, 0x22012202},
-       {0x0000a0d8, 0x221f2200},
-       {0x0000a0dc, 0x221d221e},
-       {0x0000a0e0, 0x33013302},
-       {0x0000a0e4, 0x331f3300},
-       {0x0000a0e8, 0x4402331e},
-       {0x0000a0ec, 0x44004401},
-       {0x0000a0f0, 0x441e441f},
-       {0x0000a0f4, 0x55015502},
-       {0x0000a0f8, 0x551f5500},
-       {0x0000a0fc, 0x6602551e},
+       {0x0000a0c0, 0x22072208},
+       {0x0000a0c4, 0x22052206},
+       {0x0000a0c8, 0x22032204},
+       {0x0000a0cc, 0x22012202},
+       {0x0000a0d0, 0x221f2200},
+       {0x0000a0d4, 0x221d221e},
+       {0x0000a0d8, 0x33023303},
+       {0x0000a0dc, 0x33003301},
+       {0x0000a0e0, 0x331e331f},
+       {0x0000a0e4, 0x4402331d},
+       {0x0000a0e8, 0x44004401},
+       {0x0000a0ec, 0x441e441f},
+       {0x0000a0f0, 0x55025503},
+       {0x0000a0f4, 0x55005501},
+       {0x0000a0f8, 0x551e551f},
+       {0x0000a0fc, 0x6602551d},
        {0x0000a100, 0x66006601},
        {0x0000a104, 0x661e661f},
        {0x0000a108, 0x7703661d},
@@ -636,17 +851,12 @@ static const u32 ar9485_1_1_baseband_postamble[][5] = {
        {0x0000982c, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4, 0x05eea6d4},
        {0x00009830, 0x0000059c, 0x0000059c, 0x0000059c, 0x0000059c},
        {0x00009c00, 0x00000044, 0x00000044, 0x00000044, 0x00000044},
-       {0x00009e00, 0x0372161e, 0x0372161e, 0x037216a0, 0x037216a0},
-       {0x00009e04, 0x00182020, 0x00182020, 0x00182020, 0x00182020},
        {0x00009e0c, 0x6c4000e2, 0x6d4000e2, 0x6d4000e2, 0x6c4000e2},
        {0x00009e10, 0x7ec88d2e, 0x7ec88d2e, 0x7ec80d2e, 0x7ec80d2e},
-       {0x00009e14, 0x31395d5e, 0x3139605e, 0x3139605e, 0x31395d5e},
-       {0x00009e18, 0x00000000, 0x00000000, 0x00000000, 0x00000000},
+       {0x00009e14, 0x31395d53, 0x31396053, 0x312e6053, 0x312e5d53},
        {0x00009e1c, 0x0001cf9c, 0x0001cf9c, 0x00021f9c, 0x00021f9c},
        {0x00009e20, 0x000003b5, 0x000003b5, 0x000003ce, 0x000003ce},
-       {0x00009e2c, 0x0000001c, 0x0000001c, 0x00000021, 0x00000021},
        {0x00009e3c, 0xcf946220, 0xcf946220, 0xcf946222, 0xcf946222},
-       {0x00009e44, 0x02321e27, 0x02321e27, 0x02282324, 0x02282324},
        {0x00009e48, 0x5030201a, 0x5030201a, 0x50302010, 0x50302010},
        {0x00009fc8, 0x0003f000, 0x0003f000, 0x0001a000, 0x0001a000},
        {0x0000a204, 0x01303fc0, 0x01303fc4, 0x01303fc4, 0x01303fc0},
@@ -850,4 +1060,6 @@ static const u32 ar9485_1_1_mac_core[][2] = {
        {0x000083d0, 0x000301ff},
 };
 
+#define ar9485_1_1_baseband_core_txfir_coeff_japan_2484 ar9462_2p0_baseband_core_txfir_coeff_japan_2484
+
 #endif /* INITVALS_9485_H */
index 4e125d8904a00dbb2796da796f0f5991f1054ed2..80bab1b8447af3866f796ad28c6eb3c103c0ab9c 100644 (file)
@@ -129,10 +129,10 @@ void ath_descdma_cleanup(struct ath_softc *sc, struct ath_descdma *dd,
 #define ATH_TXMAXTRY            13
 
 #define TID_TO_WME_AC(_tid)                            \
-       ((((_tid) == 0) || ((_tid) == 3)) ? WME_AC_BE : \
-        (((_tid) == 1) || ((_tid) == 2)) ? WME_AC_BK : \
-        (((_tid) == 4) || ((_tid) == 5)) ? WME_AC_VI : \
-        WME_AC_VO)
+       ((((_tid) == 0) || ((_tid) == 3)) ? IEEE80211_AC_BE :   \
+        (((_tid) == 1) || ((_tid) == 2)) ? IEEE80211_AC_BK :   \
+        (((_tid) == 4) || ((_tid) == 5)) ? IEEE80211_AC_VI :   \
+        IEEE80211_AC_VO)
 
 #define ATH_AGGR_DELIM_SZ          4
 #define ATH_AGGR_MINPLEN           256 /* in bytes, minimum packet length */
@@ -259,13 +259,10 @@ struct ath_atx_tid {
 };
 
 struct ath_node {
-#ifdef CONFIG_ATH9K_DEBUGFS
-       struct list_head list; /* for sc->nodes */
-#endif
        struct ieee80211_sta *sta; /* station struct we're part of */
        struct ieee80211_vif *vif; /* interface with which we're associated */
        struct ath_atx_tid tid[WME_NUM_TID];
-       struct ath_atx_ac ac[WME_NUM_AC];
+       struct ath_atx_ac ac[IEEE80211_NUM_ACS];
        int ps_key;
 
        u16 maxampdu;
@@ -299,9 +296,9 @@ struct ath_tx {
        struct list_head txbuf;
        struct ath_txq txq[ATH9K_NUM_TX_QUEUES];
        struct ath_descdma txdma;
-       struct ath_txq *txq_map[WME_NUM_AC];
-       u32 txq_max_pending[WME_NUM_AC];
-       u16 max_aggr_framelen[WME_NUM_AC][4][32];
+       struct ath_txq *txq_map[IEEE80211_NUM_ACS];
+       u32 txq_max_pending[IEEE80211_NUM_ACS];
+       u16 max_aggr_framelen[IEEE80211_NUM_ACS][4][32];
 };
 
 struct ath_rx_edma {
@@ -461,6 +458,12 @@ void ath9k_queue_reset(struct ath_softc *sc, enum ath_reset_type type);
 /* BTCOEX */
 /**********/
 
+#define ATH_DUMP_BTCOEX(_s, _val)                              \
+       do {                                                    \
+               len += snprintf(buf + len, size - len,          \
+                               "%20s : %10d\n", _s, (_val));   \
+       } while (0)
+
 enum bt_op_flags {
        BT_OP_PRIORITY_DETECTED,
        BT_OP_SCAN,
@@ -482,6 +485,7 @@ struct ath_btcoex {
        int rssi_count;
        struct ath_gen_timer *no_stomp_timer; /* Timer for no BT stomping */
        struct ath_mci_profile mci;
+       u8 stomp_audio;
 };
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
@@ -494,7 +498,7 @@ void ath9k_btcoex_timer_pause(struct ath_softc *sc);
 void ath9k_btcoex_handle_interrupt(struct ath_softc *sc, u32 status);
 u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc, u32 max_4ms_framelen);
 void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc);
-int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size);
+int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size);
 #else
 static inline int ath9k_init_btcoex(struct ath_softc *sc)
 {
@@ -521,8 +525,7 @@ static inline u16 ath9k_btcoex_aggr_limit(struct ath_softc *sc,
 static inline void ath9k_btcoex_stop_gen_timer(struct ath_softc *sc)
 {
 }
-static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf,
-                                   u32 len, u32 size)
+static inline int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
 {
        return 0;
 }
@@ -717,9 +720,6 @@ struct ath_softc {
 
 #ifdef CONFIG_ATH9K_DEBUGFS
        struct ath9k_debug debug;
-       spinlock_t nodes_lock;
-       struct list_head nodes; /* basically, stations */
-       unsigned int tx_complete_poll_work_seen;
 #endif
        struct ath_beacon_config cur_beacon_conf;
        struct delayed_work tx_complete_work;
index 1b48414dca95d919a3c66dc6c760ce0b7338abdc..531fffd801a34eaa11b8d483aca51ac07e7a7fab 100644 (file)
@@ -46,7 +46,7 @@ static void ath9k_beaconq_config(struct ath_softc *sc)
                qi.tqi_cwmax = 0;
        } else {
                /* Adhoc mode; important thing is to use 2x cwmin. */
-               txq = sc->tx.txq_map[WME_AC_BE];
+               txq = sc->tx.txq_map[IEEE80211_AC_BE];
                ath9k_hw_get_txq_props(ah, txq->axq_qnum, &qi_be);
                qi.tqi_aifs = qi_be.tqi_aifs;
                if (ah->slottime == ATH9K_SLOT_TIME_20)
index c90e9bc4b0262e96ebd0f626b35b55794964040e..9963b0bf9f72694630cab058621547f53eeeb237 100644 (file)
@@ -49,6 +49,7 @@ static const u32 mci_wlan_weights[ATH_BTCOEX_STOMP_MAX]
        { 0x01017d01, 0x3b3b3b01, 0x3b3b3b01, 0x3b3b3b3b }, /* STOMP_LOW */
        { 0x01017d01, 0x01010101, 0x01010101, 0x01010101 }, /* STOMP_NONE */
        { 0x01017d01, 0x013b0101, 0x3b3b0101, 0x3b3b013b }, /* STOMP_LOW_FTP */
+       { 0xffffff01, 0xffffffff, 0xffffff01, 0xffffffff }, /* STOMP_AUDIO */
 };
 
 void ath9k_hw_init_btcoex_hw(struct ath_hw *ah, int qnum)
index 2f84ab273d0c3950bc74696150aa1d1d3adc046a..6de26ea5d5fa11e190d89edd92dcec24058e1f75 100644 (file)
@@ -50,6 +50,7 @@ enum ath_stomp_type {
        ATH_BTCOEX_STOMP_LOW,
        ATH_BTCOEX_STOMP_NONE,
        ATH_BTCOEX_STOMP_LOW_FTP,
+       ATH_BTCOEX_STOMP_AUDIO,
        ATH_BTCOEX_STOMP_MAX
 };
 
index ad14fecc76c6e1eb1405448a2b1179f2a4f234b0..76b543900314079a5000d36777c8d4071e0a9c3a 100644 (file)
 #define WME_MAX_BA              WME_BA_BMP_SIZE
 #define ATH_TID_MAX_BUFS        (2 * WME_MAX_BA)
 
-/* These must match mac80211 skb queue mapping numbers */
-#define WME_AC_VO   0
-#define WME_AC_VI   1
-#define WME_AC_BE   2
-#define WME_AC_BK   3
-#define WME_NUM_AC  4
-
 #define ATH_RSSI_DUMMY_MARKER   0x127
 #define ATH_RSSI_LPF_LEN               10
 #define RSSI_LPF_THRESHOLD             -20
index a8be94b2a53abf6eb76cd2418cb0d72e81324c87..939308c25712b93c72f07e9dd9893adcea3c0d2d 100644 (file)
@@ -512,62 +512,19 @@ static const struct file_operations fops_interrupt = {
        .llseek = default_llseek,
 };
 
-#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
-#define PR(str, elem)                                                  \
-       do {                                                            \
-               len += snprintf(buf + len, size - len,                  \
-                               "%s%13u%11u%10u%10u\n", str,            \
-               sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem, \
-               sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem, \
-               sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem, \
-               sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem); \
-               if (len >= size)                          \
-                       goto done;                        \
-} while(0)
-
-#define PRX(str, elem)                                                 \
-do {                                                                   \
-       len += snprintf(buf + len, size - len,                          \
-                       "%s%13u%11u%10u%10u\n", str,                    \
-                       (unsigned int)(sc->tx.txq_map[WME_AC_BE]->elem),        \
-                       (unsigned int)(sc->tx.txq_map[WME_AC_BK]->elem),        \
-                       (unsigned int)(sc->tx.txq_map[WME_AC_VI]->elem),        \
-                       (unsigned int)(sc->tx.txq_map[WME_AC_VO]->elem));       \
-       if (len >= size)                                                \
-               goto done;                                              \
-} while(0)
-
-#define PRQLE(str, elem)                                               \
-do {                                                                   \
-       len += snprintf(buf + len, size - len,                          \
-                       "%s%13i%11i%10i%10i\n", str,                    \
-                       list_empty(&sc->tx.txq_map[WME_AC_BE]->elem),   \
-                       list_empty(&sc->tx.txq_map[WME_AC_BK]->elem),   \
-                       list_empty(&sc->tx.txq_map[WME_AC_VI]->elem),   \
-                       list_empty(&sc->tx.txq_map[WME_AC_VO]->elem));  \
-       if (len >= size)                                                \
-               goto done;                                              \
-} while (0)
-
 static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
                              size_t count, loff_t *ppos)
 {
        struct ath_softc *sc = file->private_data;
        char *buf;
-       unsigned int len = 0, size = 8000;
-       int i;
+       unsigned int len = 0, size = 2048;
        ssize_t retval = 0;
-       char tmp[32];
 
        buf = kzalloc(size, GFP_KERNEL);
        if (buf == NULL)
                return -ENOMEM;
 
-       len += sprintf(buf, "Num-Tx-Queues: %i  tx-queues-setup: 0x%x"
-                      " poll-work-seen: %u\n"
-                      "%30s %10s%10s%10s\n\n",
-                      ATH9K_NUM_TX_QUEUES, sc->tx.txqsetup,
-                      sc->tx_complete_poll_work_seen,
+       len += sprintf(buf, "%30s %10s%10s%10s\n\n",
                       "BE", "BK", "VI", "VO");
 
        PR("MPDUs Queued:    ", queued);
@@ -587,62 +544,11 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
        PR("DELIM Underrun:  ", delim_underrun);
        PR("TX-Pkts-All:     ", tx_pkts_all);
        PR("TX-Bytes-All:    ", tx_bytes_all);
-       PR("hw-put-tx-buf:   ", puttxbuf);
-       PR("hw-tx-start:     ", txstart);
-       PR("hw-tx-proc-desc: ", txprocdesc);
+       PR("HW-put-tx-buf:   ", puttxbuf);
+       PR("HW-tx-start:     ", txstart);
+       PR("HW-tx-proc-desc: ", txprocdesc);
        PR("TX-Failed:       ", txfailed);
-       len += snprintf(buf + len, size - len,
-                       "%s%11p%11p%10p%10p\n", "txq-memory-address:",
-                       sc->tx.txq_map[WME_AC_BE],
-                       sc->tx.txq_map[WME_AC_BK],
-                       sc->tx.txq_map[WME_AC_VI],
-                       sc->tx.txq_map[WME_AC_VO]);
-       if (len >= size)
-               goto done;
-
-       PRX("axq-qnum:        ", axq_qnum);
-       PRX("axq-depth:       ", axq_depth);
-       PRX("axq-ampdu_depth: ", axq_ampdu_depth);
-       PRX("axq-stopped      ", stopped);
-       PRX("tx-in-progress   ", axq_tx_inprogress);
-       PRX("pending-frames   ", pending_frames);
-       PRX("txq_headidx:     ", txq_headidx);
-       PRX("txq_tailidx:     ", txq_headidx);
-
-       PRQLE("axq_q empty:       ", axq_q);
-       PRQLE("axq_acq empty:     ", axq_acq);
-       for (i = 0; i < ATH_TXFIFO_DEPTH; i++) {
-               snprintf(tmp, sizeof(tmp) - 1, "txq_fifo[%i] empty: ", i);
-               PRQLE(tmp, txq_fifo[i]);
-       }
-
-       /* Print out more detailed queue-info */
-       for (i = 0; i <= WME_AC_BK; i++) {
-               struct ath_txq *txq = &(sc->tx.txq[i]);
-               struct ath_atx_ac *ac;
-               struct ath_atx_tid *tid;
-               if (len >= size)
-                       goto done;
-               spin_lock_bh(&txq->axq_lock);
-               if (!list_empty(&txq->axq_acq)) {
-                       ac = list_first_entry(&txq->axq_acq, struct ath_atx_ac,
-                                             list);
-                       len += snprintf(buf + len, size - len,
-                                       "txq[%i] first-ac: %p sched: %i\n",
-                                       i, ac, ac->sched);
-                       if (list_empty(&ac->tid_q) || (len >= size))
-                               goto done_for;
-                       tid = list_first_entry(&ac->tid_q, struct ath_atx_tid,
-                                              list);
-                       len += snprintf(buf + len, size - len,
-                                       " first-tid: %p sched: %i paused: %i\n",
-                                       tid, tid->sched, tid->paused);
-               }
-       done_for:
-               spin_unlock_bh(&txq->axq_lock);
-       }
 
-done:
        if (len > size)
                len = size;
 
@@ -652,62 +558,41 @@ done:
        return retval;
 }
 
-static ssize_t read_file_stations(struct file *file, char __user *user_buf,
-                                 size_t count, loff_t *ppos)
+static ssize_t read_file_queues(struct file *file, char __user *user_buf,
+                               size_t count, loff_t *ppos)
 {
        struct ath_softc *sc = file->private_data;
+       struct ath_txq *txq;
        char *buf;
-       unsigned int len = 0, size = 64000;
-       struct ath_node *an = NULL;
+       unsigned int len = 0, size = 1024;
        ssize_t retval = 0;
-       int q;
+       int i;
+       char *qname[4] = {"VO", "VI", "BE", "BK"};
 
        buf = kzalloc(size, GFP_KERNEL);
        if (buf == NULL)
                return -ENOMEM;
 
-       len += snprintf(buf + len, size - len,
-                       "Stations:\n"
-                       " tid: addr sched paused buf_q-empty an ac baw\n"
-                       " ac: addr sched tid_q-empty txq\n");
-
-       spin_lock(&sc->nodes_lock);
-       list_for_each_entry(an, &sc->nodes, list) {
-               unsigned short ma = an->maxampdu;
-               if (ma == 0)
-                       ma = 65535; /* see ath_lookup_rate */
-               len += snprintf(buf + len, size - len,
-                               "iface: %pM  sta: %pM max-ampdu: %hu mpdu-density: %uus\n",
-                               an->vif->addr, an->sta->addr, ma,
-                               (unsigned int)(an->mpdudensity));
-               if (len >= size)
-                       goto done;
-
-               for (q = 0; q < WME_NUM_TID; q++) {
-                       struct ath_atx_tid *tid = &(an->tid[q]);
-                       len += snprintf(buf + len, size - len,
-                                       " tid: %p %s %s %i %p %p %hu\n",
-                                       tid, tid->sched ? "sched" : "idle",
-                                       tid->paused ? "paused" : "running",
-                                       skb_queue_empty(&tid->buf_q),
-                                       tid->an, tid->ac, tid->baw_size);
-                       if (len >= size)
-                               goto done;
-               }
+       for (i = 0; i < IEEE80211_NUM_ACS; i++) {
+               txq = sc->tx.txq_map[i];
+               len += snprintf(buf + len, size - len, "(%s): ", qname[i]);
 
-               for (q = 0; q < WME_NUM_AC; q++) {
-                       struct ath_atx_ac *ac = &(an->ac[q]);
-                       len += snprintf(buf + len, size - len,
-                                       " ac: %p %s %i %p\n",
-                                       ac, ac->sched ? "sched" : "idle",
-                                       list_empty(&ac->tid_q), ac->txq);
-                       if (len >= size)
-                               goto done;
-               }
+               ath_txq_lock(sc, txq);
+
+               len += snprintf(buf + len, size - len, "%s: %d ",
+                               "qnum", txq->axq_qnum);
+               len += snprintf(buf + len, size - len, "%s: %2d ",
+                               "qdepth", txq->axq_depth);
+               len += snprintf(buf + len, size - len, "%s: %2d ",
+                               "ampdu-depth", txq->axq_ampdu_depth);
+               len += snprintf(buf + len, size - len, "%s: %3d ",
+                               "pending", txq->pending_frames);
+               len += snprintf(buf + len, size - len, "%s: %d\n",
+                               "stopped", txq->stopped);
+
+               ath_txq_unlock(sc, txq);
        }
 
-done:
-       spin_unlock(&sc->nodes_lock);
        if (len > size)
                len = size;
 
@@ -837,6 +722,9 @@ static ssize_t read_file_reset(struct file *file, char __user *user_buf,
        len += snprintf(buf + len, sizeof(buf) - len,
                        "%17s: %2d\n", "PLL RX Hang",
                        sc->debug.stats.reset[RESET_TYPE_PLL_HANG]);
+       len += snprintf(buf + len, sizeof(buf) - len,
+                       "%17s: %2d\n", "MCI Reset",
+                       sc->debug.stats.reset[RESET_TYPE_MCI]);
 
        if (len > sizeof(buf))
                len = sizeof(buf);
@@ -919,8 +807,8 @@ static const struct file_operations fops_xmit = {
        .llseek = default_llseek,
 };
 
-static const struct file_operations fops_stations = {
-       .read = read_file_stations,
+static const struct file_operations fops_queues = {
+       .read = read_file_queues,
        .open = simple_open,
        .owner = THIS_MODULE,
        .llseek = default_llseek,
@@ -1599,8 +1487,14 @@ static ssize_t read_file_btcoex(struct file *file, char __user *user_buf,
        if (buf == NULL)
                return -ENOMEM;
 
-       len = ath9k_dump_btcoex(sc, buf, len, size);
+       if (!sc->sc_ah->common.btcoex_enabled) {
+               len = snprintf(buf, size, "%s\n",
+                              "BTCOEX is disabled");
+               goto exit;
+       }
 
+       len = ath9k_dump_btcoex(sc, buf, size);
+exit:
        retval = simple_read_from_buffer(user_buf, count, ppos, buf, len);
        kfree(buf);
 
@@ -1638,16 +1532,16 @@ int ath9k_init_debug(struct ath_hw *ah)
                            &fops_interrupt);
        debugfs_create_file("xmit", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_xmit);
+       debugfs_create_file("queues", S_IRUSR, sc->debug.debugfs_phy, sc,
+                           &fops_queues);
        debugfs_create_u32("qlen_bk", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
-                          &sc->tx.txq_max_pending[WME_AC_BK]);
+                          &sc->tx.txq_max_pending[IEEE80211_AC_BK]);
        debugfs_create_u32("qlen_be", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
-                          &sc->tx.txq_max_pending[WME_AC_BE]);
+                          &sc->tx.txq_max_pending[IEEE80211_AC_BE]);
        debugfs_create_u32("qlen_vi", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
-                          &sc->tx.txq_max_pending[WME_AC_VI]);
+                          &sc->tx.txq_max_pending[IEEE80211_AC_VI]);
        debugfs_create_u32("qlen_vo", S_IRUSR | S_IWUSR, sc->debug.debugfs_phy,
-                          &sc->tx.txq_max_pending[WME_AC_VO]);
-       debugfs_create_file("stations", S_IRUSR, sc->debug.debugfs_phy, sc,
-                           &fops_stations);
+                          &sc->tx.txq_max_pending[IEEE80211_AC_VO]);
        debugfs_create_file("misc", S_IRUSR, sc->debug.debugfs_phy, sc,
                            &fops_misc);
        debugfs_create_file("reset", S_IRUSR, sc->debug.debugfs_phy, sc,
index 2ed9785a38fa0467a8ab8be32d30c912a5194a87..f9bee18de5a0fd2fab381fd23bbd3742dd4d3287 100644 (file)
@@ -41,6 +41,7 @@ enum ath_reset_type {
        RESET_TYPE_PLL_HANG,
        RESET_TYPE_MAC_HANG,
        RESET_TYPE_BEACON_STUCK,
+       RESET_TYPE_MCI,
        __RESET_TYPE_MAX
 };
 
@@ -178,6 +179,21 @@ struct ath_tx_stats {
        u32 txfailed;
 };
 
+/*
+ * Various utility macros to print TX/Queue counters.
+ */
+#define PR_QNUM(_n) sc->tx.txq_map[_n]->axq_qnum
+#define TXSTATS sc->debug.stats.txstats
+#define PR(str, elem)                                                  \
+       do {                                                            \
+               len += snprintf(buf + len, size - len,                  \
+                               "%s%13u%11u%10u%10u\n", str,            \
+                               TXSTATS[PR_QNUM(IEEE80211_AC_BE)].elem, \
+                               TXSTATS[PR_QNUM(IEEE80211_AC_BK)].elem, \
+                               TXSTATS[PR_QNUM(IEEE80211_AC_VI)].elem, \
+                               TXSTATS[PR_QNUM(IEEE80211_AC_VO)].elem); \
+       } while(0)
+
 #define RX_STAT_INC(c) (sc->debug.stats.rxstats.c++)
 
 /**
@@ -226,7 +242,7 @@ struct ath_rx_stats {
 
 struct ath_stats {
        struct ath_interrupt_stats istats;
-       struct ath_tx_stats txstats[ATH9K_NUM_TX_QUEUES];
+       struct ath_tx_stats txstats[IEEE80211_NUM_ACS];
        struct ath_rx_stats rxstats;
        struct ath_dfs_stats dfs_stats;
        u32 reset[__RESET_TYPE_MAX];
index ea2a6cf7ef23a86241a1232d9294eef6392f9c13..24877b00cbf4b7b97a534daaf1cc0316d8928e8c 100644 (file)
@@ -42,10 +42,15 @@ struct radar_types {
 #define MIN_PPB_THRESH 50
 #define PPB_THRESH(PPB) ((PPB * MIN_PPB_THRESH + 50) / 100)
 #define PRF2PRI(PRF) ((1000000 + PRF / 2) / PRF)
+/* percentage of pulse width tolerance */
+#define WIDTH_TOLERANCE 5
+#define WIDTH_LOWER(X) ((X*(100-WIDTH_TOLERANCE)+50)/100)
+#define WIDTH_UPPER(X) ((X*(100+WIDTH_TOLERANCE)+50)/100)
 
 #define ETSI_PATTERN(ID, WMIN, WMAX, PMIN, PMAX, PRF, PPB)     \
 {                                                              \
-       ID, WMIN, WMAX, (PRF2PRI(PMAX) - PRI_TOLERANCE),        \
+       ID, WIDTH_LOWER(WMIN), WIDTH_UPPER(WMAX),               \
+       (PRF2PRI(PMAX) - PRI_TOLERANCE),                        \
        (PRF2PRI(PMIN) * PRF + PRI_TOLERANCE), PRF, PPB * PRF,  \
        PPB_THRESH(PPB), PRI_TOLERANCE,                         \
 }
@@ -274,7 +279,7 @@ static bool dpd_set_domain(struct dfs_pattern_detector *dpd,
 
 static struct dfs_pattern_detector default_dpd = {
        .exit           = dpd_exit,
-       .set_domain     = dpd_set_domain,
+       .set_dfs_domain = dpd_set_domain,
        .add_pulse      = dpd_add_pulse,
        .region         = NL80211_DFS_UNSET,
 };
@@ -291,10 +296,11 @@ dfs_pattern_detector_init(enum nl80211_dfs_regions region)
        *dpd = default_dpd;
        INIT_LIST_HEAD(&dpd->channel_detectors);
 
-       if (dpd->set_domain(dpd, region))
+       if (dpd->set_dfs_domain(dpd, region))
                return dpd;
 
        pr_err("Could not set DFS domain to %d. ", region);
+       kfree(dpd);
        return NULL;
 }
 EXPORT_SYMBOL(dfs_pattern_detector_init);
index fd0328a30995f3fbed6f3d8d9467813553a22bc7..cda52f39f28af81cb5afb18e6d406b46d9078864 100644 (file)
@@ -62,7 +62,7 @@ struct radar_detector_specs {
 /**
  * struct dfs_pattern_detector - DFS pattern detector
  * @exit(): destructor
- * @set_domain(): set DFS domain, resets detector lines upon domain changes
+ * @set_dfs_domain(): set DFS domain, resets detector lines upon domain changes
  * @add_pulse(): add radar pulse to detector, returns true on detection
  * @region: active DFS region, NL80211_DFS_UNSET until set
  * @num_radar_types: number of different radar types
@@ -72,7 +72,7 @@ struct radar_detector_specs {
  */
 struct dfs_pattern_detector {
        void (*exit)(struct dfs_pattern_detector *dpd);
-       bool (*set_domain)(struct dfs_pattern_detector *dpd,
+       bool (*set_dfs_domain)(struct dfs_pattern_detector *dpd,
                           enum nl80211_dfs_regions region);
        bool (*add_pulse)(struct dfs_pattern_detector *dpd,
                          struct pulse_event *pe);
index a8ea57b9f49cc1836872ec3b0617d1075969b6c3..4b412aaf4f3699e65396598be9f7485f2af0754f 100644 (file)
@@ -247,6 +247,9 @@ static void ath_btcoex_period_timer(unsigned long data)
                        stomp_type = ATH_BTCOEX_STOMP_ALL;
                        timer_period = btcoex->btscan_no_stomp;
                }
+       } else if (btcoex->stomp_audio >= 5) {
+               stomp_type = ATH_BTCOEX_STOMP_AUDIO;
+               btcoex->stomp_audio = 0;
        }
 
        ath9k_hw_btcoex_bt_stomp(ah, stomp_type);
@@ -295,7 +298,7 @@ static void ath_btcoex_no_stomp_timer(void *arg)
            (!(ah->caps.hw_caps & ATH9K_HW_CAP_MCI) &&
             test_bit(BT_OP_SCAN, &btcoex->op_flags)))
                ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_NONE);
-        else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
+       else if (btcoex->bt_stomp_type == ATH_BTCOEX_STOMP_ALL)
                ath9k_hw_btcoex_bt_stomp(ah, ATH_BTCOEX_STOMP_LOW);
 
        ath9k_hw_btcoex_enable(ah);
@@ -471,7 +474,7 @@ int ath9k_init_btcoex(struct ath_softc *sc)
                r = ath_init_btcoex_timer(sc);
                if (r)
                        return -1;
-               txq = sc->tx.txq_map[WME_AC_BE];
+               txq = sc->tx.txq_map[IEEE80211_AC_BE];
                ath9k_hw_init_btcoex_hw(sc->sc_ah, txq->axq_qnum);
                sc->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
                if (ath9k_hw_mci_is_enabled(ah)) {
@@ -494,35 +497,31 @@ int ath9k_init_btcoex(struct ath_softc *sc)
        return 0;
 }
 
-int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size)
+static int ath9k_dump_mci_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
 {
-#define ATH_DUMP_BTCOEX(_s, _val)                                \
-       do {                                                     \
-               len += snprintf(buf + len, size - len,           \
-                               "%20s : %10d\n", _s, (_val));    \
-       } while (0)
-
        struct ath_btcoex *btcoex = &sc->btcoex;
        struct ath_mci_profile *mci = &btcoex->mci;
        struct ath_hw *ah = sc->sc_ah;
        struct ath_btcoex_hw *btcoex_hw = &ah->btcoex_hw;
+       u32 len = 0;
        int i;
 
        ATH_DUMP_BTCOEX("Total BT profiles", NUM_PROF(mci));
-       ATH_DUMP_BTCOEX("Number of MGMT", mci->num_mgmt);
-       ATH_DUMP_BTCOEX("Number of SCO", mci->num_sco);
-       ATH_DUMP_BTCOEX("Number of A2DP", mci->num_a2dp);
-       ATH_DUMP_BTCOEX("Number of HID", mci->num_hid);
-       ATH_DUMP_BTCOEX("Number of PAN", mci->num_pan);
-       ATH_DUMP_BTCOEX("Number of ACL", mci->num_other_acl);
-       ATH_DUMP_BTCOEX("Number of BDR", mci->num_bdr);
+       ATH_DUMP_BTCOEX("MGMT", mci->num_mgmt);
+       ATH_DUMP_BTCOEX("SCO", mci->num_sco);
+       ATH_DUMP_BTCOEX("A2DP", mci->num_a2dp);
+       ATH_DUMP_BTCOEX("HID", mci->num_hid);
+       ATH_DUMP_BTCOEX("PAN", mci->num_pan);
+       ATH_DUMP_BTCOEX("ACL", mci->num_other_acl);
+       ATH_DUMP_BTCOEX("BDR", mci->num_bdr);
        ATH_DUMP_BTCOEX("Aggr. Limit", mci->aggr_limit);
        ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type);
        ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period);
        ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle);
        ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time);
        ATH_DUMP_BTCOEX("Concurrent Tx", btcoex_hw->mci.concur_tx);
-       ATH_DUMP_BTCOEX("Concur RSSI count", btcoex->rssi_count);
+       ATH_DUMP_BTCOEX("Concurrent RSSI cnt", btcoex->rssi_count);
+
        len += snprintf(buf + len, size - len, "BT Weights: ");
        for (i = 0; i < AR9300_NUM_BT_WEIGHTS; i++)
                len += snprintf(buf + len, size - len, "%08x ",
@@ -537,9 +536,32 @@ int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 len, u32 size)
        for (i = 0; i < ATH_BTCOEX_STOMP_MAX; i++)
                len += snprintf(buf + len, size - len, "%08x ",
                                btcoex_hw->tx_prio[i]);
+
        len += snprintf(buf + len, size - len, "\n");
-#undef ATH_DUMP_BTCOEX
 
        return len;
 }
+
+static int ath9k_dump_legacy_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
+{
+
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       u32 len = 0;
+
+       ATH_DUMP_BTCOEX("Stomp Type", btcoex->bt_stomp_type);
+       ATH_DUMP_BTCOEX("BTCoex Period (msec)", btcoex->btcoex_period);
+       ATH_DUMP_BTCOEX("Duty Cycle", btcoex->duty_cycle);
+       ATH_DUMP_BTCOEX("BT Wait time", btcoex->bt_wait_time);
+
+       return len;
+}
+
+int ath9k_dump_btcoex(struct ath_softc *sc, u8 *buf, u32 size)
+{
+       if (ath9k_hw_mci_is_enabled(sc->sc_ah))
+               return ath9k_dump_mci_btcoex(sc, buf, size);
+       else
+               return ath9k_dump_legacy_btcoex(sc, buf, size);
+}
+
 #endif /* CONFIG_ATH9K_BTCOEX_SUPPORT */
index b30596fcf73a57ed5e63d81d2b465b7e4e4b7f48..96bfb18078fa14b0013d4b3e93e7544b16639746 100644 (file)
@@ -331,7 +331,7 @@ struct ath_tx_stats {
        u32 skb_success;
        u32 skb_failed;
        u32 cab_queued;
-       u32 queue_stats[WME_NUM_AC];
+       u32 queue_stats[IEEE80211_NUM_ACS];
 };
 
 struct ath_rx_stats {
@@ -493,7 +493,7 @@ struct ath9k_htc_priv {
 
        int beaconq;
        int cabq;
-       int hwq_map[WME_NUM_AC];
+       int hwq_map[IEEE80211_NUM_ACS];
 
 #ifdef CONFIG_ATH9K_BTCOEX_SUPPORT
        struct ath_btcoex btcoex;
index f42d2eb6af99302f449ef44beac8f0120238e73d..d0ce1f5bba1022087ebd45fbf7275b83c4db39e5 100644 (file)
@@ -33,7 +33,7 @@ void ath9k_htc_beaconq_config(struct ath9k_htc_priv *priv)
                qi.tqi_cwmin = 0;
                qi.tqi_cwmax = 0;
        } else if (priv->ah->opmode == NL80211_IFTYPE_ADHOC) {
-               int qnum = priv->hwq_map[WME_AC_BE];
+               int qnum = priv->hwq_map[IEEE80211_AC_BE];
 
                ath9k_hw_get_txq_props(ah, qnum, &qi_be);
 
@@ -587,9 +587,9 @@ static bool ath9k_htc_check_beacon_config(struct ath9k_htc_priv *priv,
            (priv->num_sta_vif > 1) &&
            (vif->type == NL80211_IFTYPE_STATION)) {
                beacon_configured = false;
-               ieee80211_iterate_active_interfaces_atomic(priv->hw,
-                                                          ath9k_htc_beacon_iter,
-                                                          &beacon_configured);
+               ieee80211_iterate_active_interfaces_atomic(
+                       priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+                       ath9k_htc_beacon_iter, &beacon_configured);
 
                if (beacon_configured) {
                        ath_dbg(common, CONFIG,
index 3035deb7a0cdcd5343c09733942bf0d56e5886a8..87110de577effcafa57cbfba7adad21b67bc2973 100644 (file)
@@ -218,16 +218,16 @@ static ssize_t read_file_xmit(struct file *file, char __user *user_buf,
 
        len += snprintf(buf + len, sizeof(buf) - len,
                        "%20s : %10u\n", "BE queued",
-                       priv->debug.tx_stats.queue_stats[WME_AC_BE]);
+                       priv->debug.tx_stats.queue_stats[IEEE80211_AC_BE]);
        len += snprintf(buf + len, sizeof(buf) - len,
                        "%20s : %10u\n", "BK queued",
-                       priv->debug.tx_stats.queue_stats[WME_AC_BK]);
+                       priv->debug.tx_stats.queue_stats[IEEE80211_AC_BK]);
        len += snprintf(buf + len, sizeof(buf) - len,
                        "%20s : %10u\n", "VI queued",
-                       priv->debug.tx_stats.queue_stats[WME_AC_VI]);
+                       priv->debug.tx_stats.queue_stats[IEEE80211_AC_VI]);
        len += snprintf(buf + len, sizeof(buf) - len,
                        "%20s : %10u\n", "VO queued",
-                       priv->debug.tx_stats.queue_stats[WME_AC_VO]);
+                       priv->debug.tx_stats.queue_stats[IEEE80211_AC_VO]);
 
        if (len > sizeof(buf))
                len = sizeof(buf);
index 0eacfc13c9155feb4af8cb7c4d1e4b1918c0cd39..105582d6b714956e124b291b56480d0c3c0adb6e 100644 (file)
@@ -207,7 +207,7 @@ void ath9k_htc_init_btcoex(struct ath9k_htc_priv *priv, char *product)
                priv->btcoex.bt_stomp_type = ATH_BTCOEX_STOMP_LOW;
                ath9k_hw_btcoex_init_3wire(priv->ah);
                ath_htc_init_btcoex_work(priv);
-               qnum = priv->hwq_map[WME_AC_BE];
+               qnum = priv->hwq_map[IEEE80211_AC_BE];
                ath9k_hw_init_btcoex_hw(priv->ah, qnum);
                break;
        default:
index 5ecf1287dddd8585bf0c67c6880502af173875ec..05d5ba66cac3588f64e8f6ab0545af76fbf88cbb 100644 (file)
@@ -549,20 +549,20 @@ static int ath9k_init_queues(struct ath9k_htc_priv *priv)
                goto err;
        }
 
-       if (!ath9k_htc_txq_setup(priv, WME_AC_BE)) {
+       if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BE)) {
                ath_err(common, "Unable to setup xmit queue for BE traffic\n");
                goto err;
        }
 
-       if (!ath9k_htc_txq_setup(priv, WME_AC_BK)) {
+       if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_BK)) {
                ath_err(common, "Unable to setup xmit queue for BK traffic\n");
                goto err;
        }
-       if (!ath9k_htc_txq_setup(priv, WME_AC_VI)) {
+       if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VI)) {
                ath_err(common, "Unable to setup xmit queue for VI traffic\n");
                goto err;
        }
-       if (!ath9k_htc_txq_setup(priv, WME_AC_VO)) {
+       if (!ath9k_htc_txq_setup(priv, IEEE80211_AC_VO)) {
                ath_err(common, "Unable to setup xmit queue for VO traffic\n");
                goto err;
        }
index 66f6a74c508efe40dd899e6e2e9b2decbc616368..9c07a8fa5134bb4611b93b9645c20fd0e0c414e3 100644 (file)
@@ -127,8 +127,9 @@ static void ath9k_htc_vif_reconfig(struct ath9k_htc_priv *priv)
        priv->rearm_ani = false;
        priv->reconfig_beacon = false;
 
-       ieee80211_iterate_active_interfaces_atomic(priv->hw,
-                                                  ath9k_htc_vif_iter, priv);
+       ieee80211_iterate_active_interfaces_atomic(
+               priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               ath9k_htc_vif_iter, priv);
        if (priv->rearm_ani)
                ath9k_htc_start_ani(priv);
 
@@ -165,8 +166,9 @@ static void ath9k_htc_set_bssid_mask(struct ath9k_htc_priv *priv,
                ath9k_htc_bssid_iter(&iter_data, vif->addr, vif);
 
        /* Get list of all active MAC addresses */
-       ieee80211_iterate_active_interfaces_atomic(priv->hw, ath9k_htc_bssid_iter,
-                                                  &iter_data);
+       ieee80211_iterate_active_interfaces_atomic(
+               priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               ath9k_htc_bssid_iter, &iter_data);
 
        memcpy(common->bssidmask, iter_data.mask, ETH_ALEN);
        ath_hw_setbssidmask(common);
@@ -1144,8 +1146,9 @@ static void ath9k_htc_remove_interface(struct ieee80211_hw *hw,
         */
        if ((vif->type == NL80211_IFTYPE_AP) && (priv->num_ap_vif == 0)) {
                priv->rearm_ani = false;
-               ieee80211_iterate_active_interfaces_atomic(priv->hw,
-                                                  ath9k_htc_vif_iter, priv);
+               ieee80211_iterate_active_interfaces_atomic(
+                       priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+                       ath9k_htc_vif_iter, priv);
                if (!priv->rearm_ani)
                        ath9k_htc_stop_ani(priv);
        }
@@ -1346,7 +1349,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
        struct ath9k_tx_queue_info qi;
        int ret = 0, qnum;
 
-       if (queue >= WME_NUM_AC)
+       if (queue >= IEEE80211_NUM_ACS)
                return 0;
 
        mutex_lock(&priv->mutex);
@@ -1373,7 +1376,7 @@ static int ath9k_htc_conf_tx(struct ieee80211_hw *hw,
        }
 
        if ((priv->ah->opmode == NL80211_IFTYPE_ADHOC) &&
-           (qnum == priv->hwq_map[WME_AC_BE]))
+           (qnum == priv->hwq_map[IEEE80211_AC_BE]))
                    ath9k_htc_beaconq_config(priv);
 out:
        ath9k_htc_ps_restore(priv);
@@ -1466,8 +1469,9 @@ static void ath9k_htc_bss_iter(void *data, u8 *mac, struct ieee80211_vif *vif)
 static void ath9k_htc_choose_set_bssid(struct ath9k_htc_priv *priv)
 {
        if (priv->num_sta_assoc_vif == 1) {
-               ieee80211_iterate_active_interfaces_atomic(priv->hw,
-                                                          ath9k_htc_bss_iter, priv);
+               ieee80211_iterate_active_interfaces_atomic(
+                       priv->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+                       ath9k_htc_bss_iter, priv);
                ath9k_htc_set_bssid(priv);
        }
 }
index 06cdcb772d786038b7f1e5219349a6a682b216c9..28cd50ee521a61eb60ba24fb115fa26334fd2ad1 100644 (file)
 /******/
 
 static const int subtype_txq_to_hwq[] = {
-       [WME_AC_BE] = ATH_TXQ_AC_BE,
-       [WME_AC_BK] = ATH_TXQ_AC_BK,
-       [WME_AC_VI] = ATH_TXQ_AC_VI,
-       [WME_AC_VO] = ATH_TXQ_AC_VO,
+       [IEEE80211_AC_BE] = ATH_TXQ_AC_BE,
+       [IEEE80211_AC_BK] = ATH_TXQ_AC_BK,
+       [IEEE80211_AC_VI] = ATH_TXQ_AC_VI,
+       [IEEE80211_AC_VO] = ATH_TXQ_AC_VO,
 };
 
 #define ATH9K_HTC_INIT_TXQ(subtype) do {                       \
@@ -41,15 +41,15 @@ int get_hw_qnum(u16 queue, int *hwq_map)
 {
        switch (queue) {
        case 0:
-               return hwq_map[WME_AC_VO];
+               return hwq_map[IEEE80211_AC_VO];
        case 1:
-               return hwq_map[WME_AC_VI];
+               return hwq_map[IEEE80211_AC_VI];
        case 2:
-               return hwq_map[WME_AC_BE];
+               return hwq_map[IEEE80211_AC_BE];
        case 3:
-               return hwq_map[WME_AC_BK];
+               return hwq_map[IEEE80211_AC_BK];
        default:
-               return hwq_map[WME_AC_BE];
+               return hwq_map[IEEE80211_AC_BE];
        }
 }
 
@@ -106,20 +106,20 @@ static inline enum htc_endpoint_id get_htc_epid(struct ath9k_htc_priv *priv,
 
        switch (qnum) {
        case 0:
-               TX_QSTAT_INC(WME_AC_VO);
+               TX_QSTAT_INC(IEEE80211_AC_VO);
                epid = priv->data_vo_ep;
                break;
        case 1:
-               TX_QSTAT_INC(WME_AC_VI);
+               TX_QSTAT_INC(IEEE80211_AC_VI);
                epid = priv->data_vi_ep;
                break;
        case 2:
-               TX_QSTAT_INC(WME_AC_BE);
+               TX_QSTAT_INC(IEEE80211_AC_BE);
                epid = priv->data_be_ep;
                break;
        case 3:
        default:
-               TX_QSTAT_INC(WME_AC_BK);
+               TX_QSTAT_INC(IEEE80211_AC_BK);
                epid = priv->data_bk_ep;
                break;
        }
@@ -1082,7 +1082,7 @@ static bool ath9k_rx_prepare(struct ath9k_htc_priv *priv,
        rx_status->freq = hw->conf.channel->center_freq;
        rx_status->signal =  rxbuf->rxstatus.rs_rssi + ATH_DEFAULT_NOISE_FLOOR;
        rx_status->antenna = rxbuf->rxstatus.rs_antenna;
-       rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+       rx_status->flag |= RX_FLAG_MACTIME_START;
 
        return true;
 
index 741e73dece351be33052c0e292526827b51840c8..e06bcec655a781527f51563ec771303c39ca55cd 100644 (file)
@@ -2561,11 +2561,6 @@ int ath9k_hw_fill_cap_info(struct ath_hw *ah)
                        pCap->hw_caps |= ATH9K_HW_CAP_ANT_DIV_COMB;
        }
 
-       if (AR_SREV_9485_10(ah)) {
-               pCap->pcie_lcr_extsync_en = true;
-               pCap->pcie_lcr_offset = 0x80;
-       }
-
        if (ath9k_hw_dfs_tested(ah))
                pCap->hw_caps |= ATH9K_HW_CAP_DFS;
 
index 3e73bfe2315e2dfbb94f442599355105b7cf10bb..3636dabf03e158529046f630d71328f7b7a6a17a 100644 (file)
@@ -273,8 +273,6 @@ struct ath9k_hw_capabilities {
        u8 rx_status_len;
        u8 tx_desc_len;
        u8 txs_len;
-       u16 pcie_lcr_offset;
-       bool pcie_lcr_extsync_en;
 };
 
 struct ath9k_ops_config {
@@ -877,7 +875,6 @@ struct ath_hw {
        struct ar5416IniArray iniModesTxGain;
        struct ar5416IniArray iniCckfirNormal;
        struct ar5416IniArray iniCckfirJapan2484;
-       struct ar5416IniArray ini_japan2484;
        struct ar5416IniArray iniModes_9271_ANI_reg;
        struct ar5416IniArray ini_radio_post_sys2ant;
 
@@ -930,7 +927,6 @@ struct ath_bus_ops {
        void (*read_cachesize)(struct ath_common *common, int *csz);
        bool (*eeprom_read)(struct ath_common *common, u32 off, u16 *data);
        void (*bt_coex_prep)(struct ath_common *common);
-       void (*extn_synch_en)(struct ath_common *common);
        void (*aspm_init)(struct ath_common *common);
 };
 
index 546bae93647b859e46bd95cc68f37ed0aef4526a..80cae53a33e5c5f421423a7cd5c08491197a8c81 100644 (file)
@@ -435,7 +435,7 @@ static int ath9k_init_queues(struct ath_softc *sc)
        sc->config.cabqReadytime = ATH_CABQ_READY_TIME;
        ath_cabq_update(sc);
 
-       for (i = 0; i < WME_NUM_AC; i++) {
+       for (i = 0; i < IEEE80211_NUM_ACS; i++) {
                sc->tx.txq_map[i] = ath_txq_setup(sc, ATH9K_TX_QUEUE_DATA, i);
                sc->tx.txq_map[i]->mac80211_qnum = i;
                sc->tx.txq_max_pending[i] = ATH_MAX_QDEPTH;
@@ -563,10 +563,6 @@ static int ath9k_init_softc(u16 devid, struct ath_softc *sc,
        spin_lock_init(&sc->sc_serial_rw);
        spin_lock_init(&sc->sc_pm_lock);
        mutex_init(&sc->mutex);
-#ifdef CONFIG_ATH9K_DEBUGFS
-       spin_lock_init(&sc->nodes_lock);
-       INIT_LIST_HEAD(&sc->nodes);
-#endif
 #ifdef CONFIG_ATH9K_MAC_DEBUG
        spin_lock_init(&sc->debug.samp_lock);
 #endif
index 223b9693527e0c3da4e4e111d89f4d1c2481fd36..fc6b075ad6353ee908675dcf7a89b70c2f7345f7 100644 (file)
@@ -27,9 +27,6 @@ void ath_tx_complete_poll_work(struct work_struct *work)
        struct ath_txq *txq;
        int i;
        bool needreset = false;
-#ifdef CONFIG_ATH9K_DEBUGFS
-       sc->tx_complete_poll_work_seen++;
-#endif
 
        for (i = 0; i < ATH9K_NUM_TX_QUEUES; i++)
                if (ATH_TXQ_SETUP(sc, i)) {
@@ -211,7 +208,7 @@ static bool ath_paprd_send_frame(struct ath_softc *sc, struct sk_buff *skb, int
        int time_left;
 
        memset(&txctl, 0, sizeof(txctl));
-       txctl.txq = sc->tx.txq_map[WME_AC_BE];
+       txctl.txq = sc->tx.txq_map[IEEE80211_AC_BE];
 
        memset(tx_info, 0, sizeof(*tx_info));
        tx_info->band = hw->conf.channel->band;
index 578a7234aa56dd6f10343c6564c9ae3f430c3646..0653dbc99e31ad1bf235af19d7fbbe11a4a1c8b9 100644 (file)
@@ -331,11 +331,6 @@ static void ath_node_attach(struct ath_softc *sc, struct ieee80211_sta *sta,
        u8 density;
        an = (struct ath_node *)sta->drv_priv;
 
-#ifdef CONFIG_ATH9K_DEBUGFS
-       spin_lock(&sc->nodes_lock);
-       list_add(&an->list, &sc->nodes);
-       spin_unlock(&sc->nodes_lock);
-#endif
        an->sta = sta;
        an->vif = vif;
 
@@ -352,13 +347,6 @@ static void ath_node_detach(struct ath_softc *sc, struct ieee80211_sta *sta)
 {
        struct ath_node *an = (struct ath_node *)sta->drv_priv;
 
-#ifdef CONFIG_ATH9K_DEBUGFS
-       spin_lock(&sc->nodes_lock);
-       list_del(&an->list);
-       spin_unlock(&sc->nodes_lock);
-       an->sta = NULL;
-#endif
-
        if (sc->sc_ah->caps.hw_caps & ATH9K_HW_CAP_HT)
                ath_tx_node_cleanup(sc, an);
 }
@@ -494,17 +482,6 @@ irqreturn_t ath_isr(int irq, void *dev)
        if (status & SCHED_INTR)
                sched = true;
 
-#ifdef CONFIG_PM_SLEEP
-       if (status & ATH9K_INT_BMISS) {
-               if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
-                       ath_dbg(common, ANY, "during WoW we got a BMISS\n");
-                       atomic_inc(&sc->wow_got_bmiss_intr);
-                       atomic_dec(&sc->wow_sleep_proc_intr);
-               }
-       ath_dbg(common, INTERRUPT, "beacon miss interrupt\n");
-       }
-#endif
-
        /*
         * If a FATAL or RXORN interrupt is received, we have to reset the
         * chip immediately.
@@ -523,7 +500,15 @@ irqreturn_t ath_isr(int irq, void *dev)
 
                goto chip_reset;
        }
-
+#ifdef CONFIG_PM_SLEEP
+       if (status & ATH9K_INT_BMISS) {
+               if (atomic_read(&sc->wow_sleep_proc_intr) == 0) {
+                       ath_dbg(common, ANY, "during WoW we got a BMISS\n");
+                       atomic_inc(&sc->wow_got_bmiss_intr);
+                       atomic_dec(&sc->wow_sleep_proc_intr);
+               }
+       }
+#endif
        if (status & ATH9K_INT_SWBA)
                tasklet_schedule(&sc->bcon_tasklet);
 
@@ -686,9 +671,6 @@ static int ath9k_start(struct ieee80211_hw *hw)
 
        spin_unlock_bh(&sc->sc_pcu_lock);
 
-       if (ah->caps.pcie_lcr_extsync_en && common->bus_ops->extn_synch_en)
-               common->bus_ops->extn_synch_en(common);
-
        mutex_unlock(&sc->mutex);
 
        ath9k_ps_restore(sc);
@@ -924,8 +906,9 @@ void ath9k_calculate_iter_data(struct ieee80211_hw *hw,
                ath9k_vif_iter(iter_data, vif->addr, vif);
 
        /* Get list of all active MAC addresses */
-       ieee80211_iterate_active_interfaces_atomic(sc->hw, ath9k_vif_iter,
-                                                  iter_data);
+       ieee80211_iterate_active_interfaces_atomic(
+               sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               ath9k_vif_iter, iter_data);
 }
 
 /* Called with sc->mutex held. */
@@ -975,8 +958,9 @@ static void ath9k_calculate_summary_state(struct ieee80211_hw *hw,
        if (ah->opmode == NL80211_IFTYPE_STATION &&
            old_opmode == NL80211_IFTYPE_AP &&
            test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags)) {
-               ieee80211_iterate_active_interfaces_atomic(sc->hw,
-                                                  ath9k_sta_vif_iter, sc);
+               ieee80211_iterate_active_interfaces_atomic(
+                       sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+                       ath9k_sta_vif_iter, sc);
        }
 }
 
@@ -1329,7 +1313,7 @@ static int ath9k_conf_tx(struct ieee80211_hw *hw,
        struct ath9k_tx_queue_info qi;
        int ret = 0;
 
-       if (queue >= WME_NUM_AC)
+       if (queue >= IEEE80211_NUM_ACS)
                return 0;
 
        txq = sc->tx.txq_map[queue];
@@ -1505,8 +1489,9 @@ static void ath9k_bss_info_changed(struct ieee80211_hw *hw,
                                clear_bit(SC_OP_BEACONS, &sc->sc_flags);
                }
 
-               ieee80211_iterate_active_interfaces_atomic(sc->hw,
-                                                  ath9k_bss_assoc_iter, sc);
+               ieee80211_iterate_active_interfaces_atomic(
+                       sc->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+                       ath9k_bss_assoc_iter, sc);
 
                if (!test_bit(SC_OP_PRIM_STA_VIF, &sc->sc_flags) &&
                    ah->opmode == NL80211_IFTYPE_STATION) {
@@ -1956,13 +1941,12 @@ static int ath9k_get_et_sset_count(struct ieee80211_hw *hw,
        return 0;
 }
 
-#define PR_QNUM(_n) (sc->tx.txq_map[_n]->axq_qnum)
 #define AWDATA(elem)                                                   \
        do {                                                            \
-               data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].elem; \
-               data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].elem; \
-               data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].elem; \
-               data[i++] = sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].elem; \
+               data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].elem; \
+               data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].elem; \
+               data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].elem; \
+               data[i++] = sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].elem; \
        } while (0)
 
 #define AWDATA_RX(elem)                                                \
@@ -1977,14 +1961,14 @@ static void ath9k_get_et_stats(struct ieee80211_hw *hw,
        struct ath_softc *sc = hw->priv;
        int i = 0;
 
-       data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_pkts_all +
-                    sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_pkts_all +
-                    sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_pkts_all +
-                    sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_pkts_all);
-       data[i++] = (sc->debug.stats.txstats[PR_QNUM(WME_AC_BE)].tx_bytes_all +
-                    sc->debug.stats.txstats[PR_QNUM(WME_AC_BK)].tx_bytes_all +
-                    sc->debug.stats.txstats[PR_QNUM(WME_AC_VI)].tx_bytes_all +
-                    sc->debug.stats.txstats[PR_QNUM(WME_AC_VO)].tx_bytes_all);
+       data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_pkts_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_pkts_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_pkts_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_pkts_all);
+       data[i++] = (sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BE)].tx_bytes_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_BK)].tx_bytes_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VI)].tx_bytes_all +
+                    sc->debug.stats.txstats[PR_QNUM(IEEE80211_AC_VO)].tx_bytes_all);
        AWDATA_RX(rx_pkts_all);
        AWDATA_RX(rx_bytes_all);
 
index 0dd2cbb52d65e83e6e5a8732704b936cf0d97411..706378ea3ba2ca6dd19c364b6c8e332c81af3df3 100644 (file)
@@ -207,23 +207,6 @@ skip_tuning:
        ath9k_btcoex_timer_resume(sc);
 }
 
-static void ath_mci_wait_btcal_done(struct ath_softc *sc)
-{
-       struct ath_hw *ah = sc->sc_ah;
-
-       /* Stop tx & rx */
-       ieee80211_stop_queues(sc->hw);
-       ath_stoprecv(sc);
-       ath_drain_all_txq(sc, false);
-
-       /* Wait for cal done */
-       ar9003_mci_start_reset(ah, ah->curchan);
-
-       /* Resume tx & rx */
-       ath_startrecv(sc);
-       ieee80211_wake_queues(sc->hw);
-}
-
 static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
 {
        struct ath_hw *ah = sc->sc_ah;
@@ -235,7 +218,7 @@ static void ath_mci_cal_msg(struct ath_softc *sc, u8 opcode, u8 *rx_payload)
        case MCI_GPM_BT_CAL_REQ:
                if (mci_hw->bt_state == MCI_BT_AWAKE) {
                        mci_hw->bt_state = MCI_BT_CAL_START;
-                       ath_mci_wait_btcal_done(sc);
+                       ath9k_queue_reset(sc, RESET_TYPE_MCI);
                }
                ath_dbg(common, MCI, "MCI State : %d\n", mci_hw->bt_state);
                break;
@@ -578,6 +561,8 @@ void ath_mci_intr(struct ath_softc *sc)
                mci_int_rxmsg &= ~AR_MCI_INTERRUPT_RX_MSG_GPM;
 
                while (more_data == MCI_GPM_MORE) {
+                       if (test_bit(SC_OP_HW_RESET, &sc->sc_flags))
+                               return;
 
                        pgpm = mci->gpm_buf.bf_addr;
                        offset = ar9003_mci_get_next_gpm_offset(ah, false,
@@ -744,12 +729,30 @@ void ath9k_mci_set_txpower(struct ath_softc *sc, bool setchannel,
                ath9k_hw_set_txpowerlimit(ah, sc->config.txpowlimit, false);
 }
 
+static void ath9k_mci_stomp_audio(struct ath_softc *sc)
+{
+       struct ath_hw *ah = sc->sc_ah;
+       struct ath_btcoex *btcoex = &sc->btcoex;
+       struct ath_mci_profile *mci = &btcoex->mci;
+
+       if (!mci->num_sco && !mci->num_a2dp)
+               return;
+
+       if (ah->stats.avgbrssi > 25) {
+               btcoex->stomp_audio = 0;
+               return;
+       }
+
+       btcoex->stomp_audio++;
+}
 void ath9k_mci_update_rssi(struct ath_softc *sc)
 {
        struct ath_hw *ah = sc->sc_ah;
        struct ath_btcoex *btcoex = &sc->btcoex;
        struct ath9k_hw_mci *mci_hw = &sc->sc_ah->btcoex_hw.mci;
 
+       ath9k_mci_stomp_audio(sc);
+
        if (!(mci_hw->config & ATH_MCI_CONFIG_CONCUR_TX))
                return;
 
index f088f4bf9a26a0802ca4526dce91b48213fdd09f..9553203ee6248dcd80fe9234902a61902fb6286a 100644 (file)
@@ -96,17 +96,6 @@ static bool ath_pci_eeprom_read(struct ath_common *common, u32 off, u16 *data)
        return true;
 }
 
-static void ath_pci_extn_synch_enable(struct ath_common *common)
-{
-       struct ath_softc *sc = (struct ath_softc *) common->priv;
-       struct pci_dev *pdev = to_pci_dev(sc->dev);
-       u8 lnkctl;
-
-       pci_read_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, &lnkctl);
-       lnkctl |= PCI_EXP_LNKCTL_ES;
-       pci_write_config_byte(pdev, sc->sc_ah->caps.pcie_lcr_offset, lnkctl);
-}
-
 /* Need to be called after we discover btcoex capabilities */
 static void ath_pci_aspm_init(struct ath_common *common)
 {
@@ -153,7 +142,6 @@ static const struct ath_bus_ops ath_pci_bus_ops = {
        .ath_bus_type = ATH_PCI,
        .read_cachesize = ath_pci_read_cachesize,
        .eeprom_read = ath_pci_eeprom_read,
-       .extn_synch_en = ath_pci_extn_synch_enable,
        .aspm_init = ath_pci_aspm_init,
 };
 
index 27ed80b5488133175a0b348a3f9752ebe69ed016..714558d1ba7883dfa450105b8347b3598983b99e 100644 (file)
@@ -982,16 +982,6 @@ static void ath_rc_update_per(struct ath_softc *sc,
        }
 }
 
-static void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
-                                  int xretries, int retries, u8 per)
-{
-       struct ath_rc_stats *stats = &rc->rcstats[rix];
-
-       stats->xretries += xretries;
-       stats->retries += retries;
-       stats->per = per;
-}
-
 static void ath_rc_update_ht(struct ath_softc *sc,
                             struct ath_rate_priv *ath_rc_priv,
                             struct ieee80211_tx_info *tx_info,
@@ -1065,14 +1055,6 @@ static void ath_rc_update_ht(struct ath_softc *sc,
 
 }
 
-static void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
-{
-       struct ath_rc_stats *stats;
-
-       stats = &rc->rcstats[final_rate];
-       stats->success++;
-}
-
 static void ath_rc_tx_status(struct ath_softc *sc,
                             struct ath_rate_priv *ath_rc_priv,
                             struct sk_buff *skb)
@@ -1350,7 +1332,25 @@ static void ath_rate_update(void *priv, struct ieee80211_supported_band *sband,
        }
 }
 
-#ifdef CONFIG_ATH9K_DEBUGFS
+#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
+
+void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
+{
+       struct ath_rc_stats *stats;
+
+       stats = &rc->rcstats[final_rate];
+       stats->success++;
+}
+
+void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
+                           int xretries, int retries, u8 per)
+{
+       struct ath_rc_stats *stats = &rc->rcstats[rix];
+
+       stats->xretries += xretries;
+       stats->retries += retries;
+       stats->per = per;
+}
 
 static ssize_t read_file_rcstat(struct file *file, char __user *user_buf,
                                size_t count, loff_t *ppos)
@@ -1428,10 +1428,17 @@ static void ath_rate_add_sta_debugfs(void *priv, void *priv_sta,
                                     struct dentry *dir)
 {
        struct ath_rate_priv *rc = priv_sta;
-       debugfs_create_file("rc_stats", S_IRUGO, dir, rc, &fops_rcstat);
+       rc->debugfs_rcstats = debugfs_create_file("rc_stats", S_IRUGO,
+                                                 dir, rc, &fops_rcstat);
+}
+
+static void ath_rate_remove_sta_debugfs(void *priv, void *priv_sta)
+{
+       struct ath_rate_priv *rc = priv_sta;
+       debugfs_remove(rc->debugfs_rcstats);
 }
 
-#endif /* CONFIG_ATH9K_DEBUGFS */
+#endif /* CONFIG_MAC80211_DEBUGFS && CONFIG_ATH9K_DEBUGFS */
 
 static void *ath_rate_alloc(struct ieee80211_hw *hw, struct dentry *debugfsdir)
 {
@@ -1476,8 +1483,10 @@ static struct rate_control_ops ath_rate_ops = {
        .free = ath_rate_free,
        .alloc_sta = ath_rate_alloc_sta,
        .free_sta = ath_rate_free_sta,
-#ifdef CONFIG_ATH9K_DEBUGFS
+
+#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
        .add_sta_debugfs = ath_rate_add_sta_debugfs,
+       .remove_sta_debugfs = ath_rate_remove_sta_debugfs,
 #endif
 };
 
index 268e67dc5fb2d945a26a332081b32167d9e133dc..267dbfcfaa96b8cb8b5311bd484d8e9908f838bc 100644 (file)
@@ -211,10 +211,26 @@ struct ath_rate_priv {
        struct ath_rateset neg_ht_rates;
        const struct ath_rate_table *rate_table;
 
+#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
        struct dentry *debugfs_rcstats;
        struct ath_rc_stats rcstats[RATE_TABLE_SIZE];
+#endif
 };
 
+#if defined(CONFIG_MAC80211_DEBUGFS) && defined(CONFIG_ATH9K_DEBUGFS)
+void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate);
+void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
+                           int xretries, int retries, u8 per);
+#else
+static inline void ath_debug_stat_rc(struct ath_rate_priv *rc, int final_rate)
+{
+}
+static inline void ath_debug_stat_retries(struct ath_rate_priv *rc, int rix,
+                                         int xretries, int retries, u8 per)
+{
+}
+#endif
+
 #ifdef CONFIG_ATH9K_RATE_CONTROL
 int ath_rate_control_register(void);
 void ath_rate_control_unregister(void);
index a04028bce28bbb2f9a5194d9c07b698d89ec6fc5..6aafbb77c498038738357b4178f9b7e2a6f6d2cc 100644 (file)
@@ -976,7 +976,7 @@ static int ath9k_rx_skb_preprocess(struct ath_common *common,
        rx_status->freq = hw->conf.channel->center_freq;
        rx_status->signal = ah->noise + rx_stats->rs_rssi;
        rx_status->antenna = rx_stats->rs_antenna;
-       rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+       rx_status->flag |= RX_FLAG_MACTIME_START;
        if (rx_stats->rs_moreaggr)
                rx_status->flag |= RX_FLAG_NO_SIGNAL_VAL;
 
index 741918a2027b56ebe0f561d5175e8a129b8a3059..34130943f9ded90fb27a558b08aa8fb9c08e0cd9 100644 (file)
@@ -1354,10 +1354,10 @@ struct ath_txq *ath_txq_setup(struct ath_softc *sc, int qtype, int subtype)
        struct ath_hw *ah = sc->sc_ah;
        struct ath9k_tx_queue_info qi;
        static const int subtype_txq_to_hwq[] = {
-               [WME_AC_BE] = ATH_TXQ_AC_BE,
-               [WME_AC_BK] = ATH_TXQ_AC_BK,
-               [WME_AC_VI] = ATH_TXQ_AC_VI,
-               [WME_AC_VO] = ATH_TXQ_AC_VO,
+               [IEEE80211_AC_BE] = ATH_TXQ_AC_BE,
+               [IEEE80211_AC_BK] = ATH_TXQ_AC_BK,
+               [IEEE80211_AC_VI] = ATH_TXQ_AC_VI,
+               [IEEE80211_AC_VO] = ATH_TXQ_AC_VO,
        };
        int axq_qnum, i;
 
@@ -2319,6 +2319,8 @@ void ath_tx_edma_tasklet(struct ath_softc *sc)
 
                ath_txq_lock(sc, txq);
 
+               TX_STAT_INC(txq->axq_qnum, txprocdesc);
+
                if (list_empty(&txq->txq_fifo[txq->txq_tailidx])) {
                        ath_txq_unlock(sc, txq);
                        return;
@@ -2464,7 +2466,7 @@ void ath_tx_node_init(struct ath_softc *sc, struct ath_node *an)
        }
 
        for (acno = 0, ac = &an->ac[acno];
-            acno < WME_NUM_AC; acno++, ac++) {
+            acno < IEEE80211_NUM_ACS; acno++, ac++) {
                ac->sched    = false;
                ac->txq = sc->tx.txq_map[acno];
                INIT_LIST_HEAD(&ac->tid_q);
index 24ac2876a7337ad2a015f69a4f273165d3d8d7f0..aaebecd19e5975f449bdd73bcc9c73411b6f37af 100644 (file)
 #include "fwcmd.h"
 #include "version.h"
 
-#define MAKE_STR(symbol) #symbol
-#define TO_STR(symbol) MAKE_STR(symbol)
-#define CARL9170FW_API_VER_STR TO_STR(CARL9170FW_API_MAX_VER)
-MODULE_VERSION(CARL9170FW_API_VER_STR ":" CARL9170FW_VERSION_GIT);
-
 static const u8 otus_magic[4] = { OTUS_MAGIC };
 
 static const void *carl9170_fw_find_desc(struct ar9170 *ar, const u8 descid[4],
index 136510edf3cf819285d8f72f5cb3afff0ee3683e..8cb206a89083aaa314868ef2c07b906181fe6689 100644 (file)
@@ -796,7 +796,7 @@ void b43_rx(struct b43_wldev *dev, struct sk_buff *skb, const void *_rxhdr)
                status.mactime += mactime;
                if (low_mactime_now <= mactime)
                        status.mactime -= 0x10000;
-               status.flag |= RX_FLAG_MACTIME_MPDU;
+               status.flag |= RX_FLAG_MACTIME_START;
        }
 
        chanid = (chanstat & B43_RX_CHAN_ID) >> B43_RX_CHAN_ID_SHIFT;
index b8ffea6f5c64743df59f78c94d40093b8fbeb5ea..849a28c803023e03570d69ca8d6de8f60462a6c6 100644 (file)
@@ -557,7 +557,7 @@ void b43legacy_rx(struct b43legacy_wldev *dev,
                status.mactime += mactime;
                if (low_mactime_now <= mactime)
                        status.mactime -= 0x10000;
-               status.flag |= RX_FLAG_MACTIME_MPDU;
+               status.flag |= RX_FLAG_MACTIME_START;
        }
 
        chanid = (chanstat & B43legacy_RX_CHAN_ID) >>
index c9d811eb6556bfa4494155391398c2bb2b1df815..1d92d874ebb61e487a33a2a8827e864ef39f1a15 100644 (file)
@@ -55,13 +55,16 @@ config BRCMFMAC_USB
          IEEE802.11n embedded FullMAC WLAN driver. Say Y if you want to
          use the driver for an USB wireless card.
 
-config BRCMISCAN
-       bool "Broadcom I-Scan (OBSOLETE)"
-       depends on BRCMFMAC
+config BRCM_TRACING
+       bool "Broadcom device tracing"
+       depends on BRCMSMAC || BRCMFMAC
        ---help---
-         This option enables the I-Scan method. By default fullmac uses the
-         new E-Scan method which uses less memory in firmware and gives no
-         limitation on the number of scan results.
+         If you say Y here, the Broadcom wireless drivers will register
+         with ftrace to dump event information into the trace ringbuffer.
+         Tracing can be enabled at runtime to aid in debugging wireless
+         issues. This option adds a small amount of overhead when tracing
+         is disabled. If unsure, say Y to allow developers to better help
+         you when wireless problems occur.
 
 config BRCMDBG
        bool "Broadcom driver debug functions"
index fe80b637c519af11d98f7c69209fc6766dfb7eb9..1a6661a9f008122f52288556b09237572ae71bf6 100644 (file)
@@ -25,6 +25,7 @@ obj-$(CONFIG_BRCMFMAC) += brcmfmac.o
 brcmfmac-objs += \
                wl_cfg80211.o \
                fwil.o \
+               fweh.o \
                dhd_cdc.o \
                dhd_common.o \
                dhd_linux.o
index 3b2c4c20e7fcfcccaa2a6706108473f805c0f13b..334ddab4a8c59ae8c4563d4542244c1e6d2f3875 100644 (file)
@@ -42,7 +42,8 @@
 #ifdef CONFIG_BRCMFMAC_SDIO_OOB
 static irqreturn_t brcmf_sdio_irqhandler(int irq, void *dev_id)
 {
-       struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(dev_id);
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev_id);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 
        brcmf_dbg(INTR, "oob intr triggered\n");
 
@@ -71,7 +72,7 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
        brcmf_dbg(ERROR, "requesting irq %d\n", sdiodev->irq);
        ret = request_irq(sdiodev->irq, brcmf_sdio_irqhandler,
                          sdiodev->irq_flags, "brcmf_oob_intr",
-                         &sdiodev->func[1]->card->dev);
+                         &sdiodev->func[1]->dev);
        if (ret != 0)
                return ret;
        spin_lock_init(&sdiodev->irq_en_lock);
@@ -84,6 +85,8 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
                return ret;
        sdiodev->irq_wake = true;
 
+       sdio_claim_host(sdiodev->func[1]);
+
        /* must configure SDIO_CCCR_IENx to enable irq */
        data = brcmf_sdio_regrb(sdiodev, SDIO_CCCR_IENx, &ret);
        data |= 1 << SDIO_FUNC_1 | 1 << SDIO_FUNC_2 | 1;
@@ -95,6 +98,8 @@ int brcmf_sdio_intr_register(struct brcmf_sdio_dev *sdiodev)
                data |= SDIO_SEPINT_ACT_HI;
        brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, data, &ret);
 
+       sdio_release_host(sdiodev->func[1]);
+
        return 0;
 }
 
@@ -102,14 +107,16 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
 {
        brcmf_dbg(TRACE, "Entering\n");
 
+       sdio_claim_host(sdiodev->func[1]);
        brcmf_sdio_regwb(sdiodev, SDIO_CCCR_BRCM_SEPINT, 0, NULL);
        brcmf_sdio_regwb(sdiodev, SDIO_CCCR_IENx, 0, NULL);
+       sdio_release_host(sdiodev->func[1]);
 
        if (sdiodev->irq_wake) {
                disable_irq_wake(sdiodev->irq);
                sdiodev->irq_wake = false;
        }
-       free_irq(sdiodev->irq, &sdiodev->func[1]->card->dev);
+       free_irq(sdiodev->irq, &sdiodev->func[1]->dev);
        sdiodev->irq_en = false;
 
        return 0;
@@ -117,7 +124,8 @@ int brcmf_sdio_intr_unregister(struct brcmf_sdio_dev *sdiodev)
 #else          /* CONFIG_BRCMFMAC_SDIO_OOB */
 static void brcmf_sdio_irqhandler(struct sdio_func *func)
 {
-       struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
+       struct brcmf_bus *bus_if = dev_get_drvdata(&func->dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 
        brcmf_dbg(INTR, "ib intr triggered\n");
 
@@ -249,9 +257,7 @@ u8 brcmf_sdio_regrb(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
        int retval;
 
        brcmf_dbg(INFO, "addr:0x%08x\n", addr);
-       sdio_claim_host(sdiodev->func[1]);
        retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
-       sdio_release_host(sdiodev->func[1]);
        brcmf_dbg(INFO, "data:0x%02x\n", data);
 
        if (ret)
@@ -266,9 +272,7 @@ u32 brcmf_sdio_regrl(struct brcmf_sdio_dev *sdiodev, u32 addr, int *ret)
        int retval;
 
        brcmf_dbg(INFO, "addr:0x%08x\n", addr);
-       sdio_claim_host(sdiodev->func[1]);
        retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, false);
-       sdio_release_host(sdiodev->func[1]);
        brcmf_dbg(INFO, "data:0x%08x\n", data);
 
        if (ret)
@@ -283,9 +287,7 @@ void brcmf_sdio_regwb(struct brcmf_sdio_dev *sdiodev, u32 addr,
        int retval;
 
        brcmf_dbg(INFO, "addr:0x%08x, data:0x%02x\n", addr, data);
-       sdio_claim_host(sdiodev->func[1]);
        retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
-       sdio_release_host(sdiodev->func[1]);
 
        if (ret)
                *ret = retval;
@@ -297,9 +299,7 @@ void brcmf_sdio_regwl(struct brcmf_sdio_dev *sdiodev, u32 addr,
        int retval;
 
        brcmf_dbg(INFO, "addr:0x%08x, data:0x%08x\n", addr, data);
-       sdio_claim_host(sdiodev->func[1]);
        retval = brcmf_sdio_regrw_helper(sdiodev, addr, &data, true);
-       sdio_release_host(sdiodev->func[1]);
 
        if (ret)
                *ret = retval;
@@ -364,8 +364,6 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
        brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
                  fn, addr, pkt->len);
 
-       sdio_claim_host(sdiodev->func[1]);
-
        width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
        err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
        if (err)
@@ -376,8 +374,6 @@ brcmf_sdcard_recv_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
                                         fn, addr, pkt);
 
 done:
-       sdio_release_host(sdiodev->func[1]);
-
        return err;
 }
 
@@ -391,8 +387,6 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
        brcmf_dbg(INFO, "fun = %d, addr = 0x%x, size = %d\n",
                  fn, addr, pktq->qlen);
 
-       sdio_claim_host(sdiodev->func[1]);
-
        width = (flags & SDIO_REQ_4BYTE) ? 4 : 2;
        err = brcmf_sdcard_recv_prepare(sdiodev, fn, flags, width, &addr);
        if (err)
@@ -403,8 +397,6 @@ int brcmf_sdcard_recv_chain(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
                                        pktq);
 
 done:
-       sdio_release_host(sdiodev->func[1]);
-
        return err;
 }
 
@@ -446,8 +438,6 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
        if (flags & SDIO_REQ_ASYNC)
                return -ENOTSUPP;
 
-       sdio_claim_host(sdiodev->func[1]);
-
        if (bar0 != sdiodev->sbwad) {
                err = brcmf_sdcard_set_sbaddr_window(sdiodev, bar0);
                if (err)
@@ -467,8 +457,6 @@ brcmf_sdcard_send_pkt(struct brcmf_sdio_dev *sdiodev, u32 addr, uint fn,
                                         addr, pkt);
 
 done:
-       sdio_release_host(sdiodev->func[1]);
-
        return err;
 }
 
@@ -510,10 +498,8 @@ int brcmf_sdcard_abort(struct brcmf_sdio_dev *sdiodev, uint fn)
        brcmf_dbg(TRACE, "Enter\n");
 
        /* issue abort cmd52 command through F0 */
-       sdio_claim_host(sdiodev->func[1]);
        brcmf_sdioh_request_byte(sdiodev, SDIOH_WRITE, SDIO_FUNC_0,
                                 SDIO_CCCR_ABORT, &t_func);
-       sdio_release_host(sdiodev->func[1]);
 
        brcmf_dbg(TRACE, "Exit\n");
        return 0;
@@ -530,9 +516,6 @@ int brcmf_sdio_probe(struct brcmf_sdio_dev *sdiodev)
 
        regs = SI_ENUM_BASE;
 
-       /* Report the BAR, to fix if needed */
-       sdiodev->sbwad = SI_ENUM_BASE;
-
        /* try to attach to the target device */
        sdiodev->bus = brcmf_sdbrcm_probe(regs, sdiodev);
        if (!sdiodev->bus) {
@@ -551,6 +534,8 @@ EXPORT_SYMBOL(brcmf_sdio_probe);
 
 int brcmf_sdio_remove(struct brcmf_sdio_dev *sdiodev)
 {
+       sdiodev->bus_if->state = BRCMF_BUS_DOWN;
+
        if (sdiodev->bus) {
                brcmf_sdbrcm_disconnect(sdiodev->bus);
                sdiodev->bus = NULL;
index c3247d5b3c222bfcc6ab8a05236515be073f55b6..a80050223710b7c7a1959d014d46522600878856 100644 (file)
@@ -372,9 +372,7 @@ static int brcmf_sdioh_enablefuncs(struct brcmf_sdio_dev *sdiodev)
        }
 
        /* Enable Function 1 */
-       sdio_claim_host(sdiodev->func[1]);
        err_ret = sdio_enable_func(sdiodev->func[1]);
-       sdio_release_host(sdiodev->func[1]);
        if (err_ret)
                brcmf_dbg(ERROR, "Failed to enable F1 Err: 0x%08x\n", err_ret);
 
@@ -393,16 +391,14 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
        sdiodev->num_funcs = 2;
 
        sdio_claim_host(sdiodev->func[1]);
+
        err_ret = sdio_set_block_size(sdiodev->func[1], SDIO_FUNC1_BLOCKSIZE);
-       sdio_release_host(sdiodev->func[1]);
        if (err_ret) {
                brcmf_dbg(ERROR, "Failed to set F1 blocksize\n");
                goto out;
        }
 
-       sdio_claim_host(sdiodev->func[2]);
        err_ret = sdio_set_block_size(sdiodev->func[2], SDIO_FUNC2_BLOCKSIZE);
-       sdio_release_host(sdiodev->func[2]);
        if (err_ret) {
                brcmf_dbg(ERROR, "Failed to set F2 blocksize\n");
                goto out;
@@ -411,6 +407,7 @@ int brcmf_sdioh_attach(struct brcmf_sdio_dev *sdiodev)
        brcmf_sdioh_enablefuncs(sdiodev);
 
 out:
+       sdio_release_host(sdiodev->func[1]);
        brcmf_dbg(TRACE, "Done\n");
        return err_ret;
 }
@@ -459,95 +456,106 @@ static inline int brcmf_sdio_getintrcfg(struct brcmf_sdio_dev *sdiodev)
 #endif         /* CONFIG_BRCMFMAC_SDIO_OOB */
 
 static int brcmf_ops_sdio_probe(struct sdio_func *func,
-                             const struct sdio_device_id *id)
+                               const struct sdio_device_id *id)
 {
-       int ret = 0;
+       int err;
        struct brcmf_sdio_dev *sdiodev;
        struct brcmf_bus *bus_if;
 
        brcmf_dbg(TRACE, "Enter\n");
-       brcmf_dbg(TRACE, "func->class=%x\n", func->class);
-       brcmf_dbg(TRACE, "sdio_vendor: 0x%04x\n", func->vendor);
-       brcmf_dbg(TRACE, "sdio_device: 0x%04x\n", func->device);
-       brcmf_dbg(TRACE, "Function#: 0x%04x\n", func->num);
-
-       if (func->num == 1) {
-               if (dev_get_drvdata(&func->card->dev)) {
-                       brcmf_dbg(ERROR, "card private drvdata occupied\n");
-                       return -ENXIO;
-               }
-               bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
-               if (!bus_if)
-                       return -ENOMEM;
-               sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
-               if (!sdiodev) {
-                       kfree(bus_if);
-                       return -ENOMEM;
-               }
-               sdiodev->func[0] = func;
-               sdiodev->func[1] = func;
-               sdiodev->bus_if = bus_if;
-               bus_if->bus_priv.sdio = sdiodev;
-               bus_if->type = SDIO_BUS;
-               bus_if->align = BRCMF_SDALIGN;
-               dev_set_drvdata(&func->card->dev, sdiodev);
-
-               atomic_set(&sdiodev->suspend, false);
-               init_waitqueue_head(&sdiodev->request_byte_wait);
-               init_waitqueue_head(&sdiodev->request_word_wait);
-               init_waitqueue_head(&sdiodev->request_chain_wait);
-               init_waitqueue_head(&sdiodev->request_buffer_wait);
+       brcmf_dbg(TRACE, "Class=%x\n", func->class);
+       brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
+       brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
+       brcmf_dbg(TRACE, "Function#: %d\n", func->num);
+
+       /* Consume func num 1 but dont do anything with it. */
+       if (func->num == 1)
+               return 0;
+
+       /* Ignore anything but func 2 */
+       if (func->num != 2)
+               return -ENODEV;
+
+       bus_if = kzalloc(sizeof(struct brcmf_bus), GFP_KERNEL);
+       if (!bus_if)
+               return -ENOMEM;
+       sdiodev = kzalloc(sizeof(struct brcmf_sdio_dev), GFP_KERNEL);
+       if (!sdiodev) {
+               kfree(bus_if);
+               return -ENOMEM;
        }
 
-       if (func->num == 2) {
-               sdiodev = dev_get_drvdata(&func->card->dev);
-               if ((!sdiodev) || (sdiodev->func[1]->card != func->card))
-                       return -ENODEV;
-
-               ret = brcmf_sdio_getintrcfg(sdiodev);
-               if (ret)
-                       return ret;
-               sdiodev->func[2] = func;
+       sdiodev->func[0] = func->card->sdio_func[0];
+       sdiodev->func[1] = func->card->sdio_func[0];
+       sdiodev->func[2] = func;
 
-               bus_if = sdiodev->bus_if;
-               sdiodev->dev = &func->dev;
-               dev_set_drvdata(&func->dev, bus_if);
+       sdiodev->bus_if = bus_if;
+       bus_if->bus_priv.sdio = sdiodev;
+       bus_if->align = BRCMF_SDALIGN;
+       dev_set_drvdata(&func->dev, bus_if);
+       dev_set_drvdata(&sdiodev->func[1]->dev, bus_if);
+       sdiodev->dev = &sdiodev->func[1]->dev;
 
-               brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
-               ret = brcmf_sdio_probe(sdiodev);
+       atomic_set(&sdiodev->suspend, false);
+       init_waitqueue_head(&sdiodev->request_byte_wait);
+       init_waitqueue_head(&sdiodev->request_word_wait);
+       init_waitqueue_head(&sdiodev->request_chain_wait);
+       init_waitqueue_head(&sdiodev->request_buffer_wait);
+       err = brcmf_sdio_getintrcfg(sdiodev);
+       if (err)
+               goto fail;
+
+       brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_probe...\n");
+       err = brcmf_sdio_probe(sdiodev);
+       if (err) {
+               brcmf_dbg(ERROR, "F2 error, probe failed %d...\n", err);
+               goto fail;
        }
+       brcmf_dbg(TRACE, "F2 init completed...\n");
+       return 0;
 
-       return ret;
+fail:
+       dev_set_drvdata(&func->dev, NULL);
+       dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
+       kfree(sdiodev);
+       kfree(bus_if);
+       return err;
 }
 
 static void brcmf_ops_sdio_remove(struct sdio_func *func)
 {
        struct brcmf_bus *bus_if;
        struct brcmf_sdio_dev *sdiodev;
+
        brcmf_dbg(TRACE, "Enter\n");
-       brcmf_dbg(INFO, "func->class=%x\n", func->class);
-       brcmf_dbg(INFO, "sdio_vendor: 0x%04x\n", func->vendor);
-       brcmf_dbg(INFO, "sdio_device: 0x%04x\n", func->device);
-       brcmf_dbg(INFO, "Function#: 0x%04x\n", func->num);
+       brcmf_dbg(TRACE, "sdio vendor ID: 0x%04x\n", func->vendor);
+       brcmf_dbg(TRACE, "sdio device ID: 0x%04x\n", func->device);
+       brcmf_dbg(TRACE, "Function: %d\n", func->num);
 
-       if (func->num == 2) {
-               bus_if = dev_get_drvdata(&func->dev);
+       if (func->num != 1 && func->num != 2)
+               return;
+
+       bus_if = dev_get_drvdata(&func->dev);
+       if (bus_if) {
                sdiodev = bus_if->bus_priv.sdio;
-               brcmf_dbg(TRACE, "F2 found, calling brcmf_sdio_remove...\n");
                brcmf_sdio_remove(sdiodev);
-               dev_set_drvdata(&func->card->dev, NULL);
-               dev_set_drvdata(&func->dev, NULL);
+
+               dev_set_drvdata(&sdiodev->func[1]->dev, NULL);
+               dev_set_drvdata(&sdiodev->func[2]->dev, NULL);
+
                kfree(bus_if);
                kfree(sdiodev);
        }
+
+       brcmf_dbg(TRACE, "Exit\n");
 }
 
 #ifdef CONFIG_PM_SLEEP
 static int brcmf_sdio_suspend(struct device *dev)
 {
        mmc_pm_flag_t sdio_flags;
-       struct sdio_func *func = dev_to_sdio_func(dev);
-       struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        int ret = 0;
 
        brcmf_dbg(TRACE, "\n");
@@ -573,8 +581,8 @@ static int brcmf_sdio_suspend(struct device *dev)
 
 static int brcmf_sdio_resume(struct device *dev)
 {
-       struct sdio_func *func = dev_to_sdio_func(dev);
-       struct brcmf_sdio_dev *sdiodev = dev_get_drvdata(&func->card->dev);
+       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
+       struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
 
        brcmf_sdio_wdtmr_enable(sdiodev, true);
        atomic_set(&sdiodev->suspend, false);
index 8704daa2758fc90919157e91313d03a1bc722d6f..24bc4e3e162bba09693a6a84674f0a8b102b6247 100644 (file)
@@ -23,6 +23,8 @@
 
 #define BRCMF_VERSION_STR              "4.218.248.5"
 
+#include "fweh.h"
+
 /*******************************************************************************
  * IO codes that are interpreted by dongle firmware
  ******************************************************************************/
 #define BRCMF_C_GET_SSID                       25
 #define BRCMF_C_SET_SSID                       26
 #define BRCMF_C_GET_CHANNEL                    29
+#define BRCMF_C_SET_CHANNEL                    30
 #define BRCMF_C_GET_SRL                                31
+#define BRCMF_C_SET_SRL                                32
 #define BRCMF_C_GET_LRL                                33
+#define BRCMF_C_SET_LRL                                34
 #define BRCMF_C_GET_RADIO                      37
 #define BRCMF_C_SET_RADIO                      38
 #define BRCMF_C_GET_PHYTYPE                    39
@@ -58,6 +63,7 @@
 #define BRCMF_C_SET_COUNTRY                    84
 #define BRCMF_C_GET_PM                         85
 #define BRCMF_C_SET_PM                         86
+#define BRCMF_C_GET_CURR_RATESET               114
 #define BRCMF_C_GET_AP                         117
 #define BRCMF_C_SET_AP                         118
 #define BRCMF_C_GET_RSSI                       127
@@ -65,6 +71,7 @@
 #define BRCMF_C_SET_WSEC                       134
 #define BRCMF_C_GET_PHY_NOISE                  135
 #define BRCMF_C_GET_BSS_INFO                   136
+#define BRCMF_C_GET_PHYLIST                    180
 #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_SCAN_PARAMS_COUNT_MASK 0x0000ffff
 #define BRCMF_SCAN_PARAMS_NSSID_SHIFT 16
 
-#define BRCMF_SCAN_ACTION_START      1
-#define BRCMF_SCAN_ACTION_CONTINUE   2
-#define WL_SCAN_ACTION_ABORT      3
-
-#define BRCMF_ISCAN_REQ_VERSION 1
-
-/* brcmf_iscan_results status values */
-#define BRCMF_SCAN_RESULTS_SUCCESS     0
-#define BRCMF_SCAN_RESULTS_PARTIAL     1
-#define BRCMF_SCAN_RESULTS_PENDING     2
-#define BRCMF_SCAN_RESULTS_ABORTED     3
-#define BRCMF_SCAN_RESULTS_NO_MEM      4
-
-/* Indicates this key is using soft encrypt */
-#define WL_SOFT_KEY    (1 << 0)
 /* primary (ie tx) key */
 #define BRCMF_PRIMARY_KEY      (1 << 1)
-/* Reserved for backward compat */
-#define WL_KF_RES_4    (1 << 4)
-/* Reserved for backward compat */
-#define WL_KF_RES_5    (1 << 5)
-/* Indicates a group key for a IBSS PEER */
-#define WL_IBSS_PEER_GROUP_KEY (1 << 6)
 
 /* For supporting multiple interfaces */
 #define BRCMF_MAX_IFS  16
 #define DOT11_BSSTYPE_ANY                      2
 #define DOT11_MAX_DEFAULT_KEYS 4
 
-#define BRCMF_EVENT_MSG_LINK           0x01
-#define BRCMF_EVENT_MSG_FLUSHTXQ       0x02
-#define BRCMF_EVENT_MSG_GROUP          0x04
-
 #define BRCMF_ESCAN_REQ_VERSION 1
 
 #define WLC_BSS_RSSI_ON_CHANNEL                0x0002
 #define BRCMF_MAXRATES_IN_SET          16      /* max # of rates in rateset */
 #define BRCMF_STA_ASSOC                        0x10            /* Associated */
 
-struct brcmf_event_msg {
-       __be16 version;
-       __be16 flags;
-       __be32 event_type;
-       __be32 status;
-       __be32 reason;
-       __be32 auth_type;
-       __be32 datalen;
-       u8 addr[ETH_ALEN];
-       char ifname[IFNAMSIZ];
-       u8 ifidx;
-       u8 bsscfgidx;
-} __packed;
-
-struct brcm_ethhdr {
-       u16 subtype;
-       u16 length;
-       u8 version;
-       u8 oui[3];
-       u16 usr_subtype;
-} __packed;
-
-struct brcmf_event {
-       struct ethhdr eth;
-       struct brcm_ethhdr hdr;
-       struct brcmf_event_msg msg;
-} __packed;
-
-/* event codes sent by the dongle to this driver */
-#define BRCMF_E_SET_SSID                       0
-#define BRCMF_E_JOIN                           1
-#define BRCMF_E_START                          2
-#define BRCMF_E_AUTH                           3
-#define BRCMF_E_AUTH_IND                       4
-#define BRCMF_E_DEAUTH                         5
-#define BRCMF_E_DEAUTH_IND                     6
-#define BRCMF_E_ASSOC                          7
-#define BRCMF_E_ASSOC_IND                      8
-#define BRCMF_E_REASSOC                                9
-#define BRCMF_E_REASSOC_IND                    10
-#define BRCMF_E_DISASSOC                       11
-#define BRCMF_E_DISASSOC_IND                   12
-#define BRCMF_E_QUIET_START                    13
-#define BRCMF_E_QUIET_END                      14
-#define BRCMF_E_BEACON_RX                      15
-#define BRCMF_E_LINK                           16
-#define BRCMF_E_MIC_ERROR                      17
-#define BRCMF_E_NDIS_LINK                      18
-#define BRCMF_E_ROAM                           19
-#define BRCMF_E_TXFAIL                         20
-#define BRCMF_E_PMKID_CACHE                    21
-#define BRCMF_E_RETROGRADE_TSF                 22
-#define BRCMF_E_PRUNE                          23
-#define BRCMF_E_AUTOAUTH                       24
-#define BRCMF_E_EAPOL_MSG                      25
-#define BRCMF_E_SCAN_COMPLETE                  26
-#define BRCMF_E_ADDTS_IND                      27
-#define BRCMF_E_DELTS_IND                      28
-#define BRCMF_E_BCNSENT_IND                    29
-#define BRCMF_E_BCNRX_MSG                      30
-#define BRCMF_E_BCNLOST_MSG                    31
-#define BRCMF_E_ROAM_PREP                      32
-#define BRCMF_E_PFN_NET_FOUND                  33
-#define BRCMF_E_PFN_NET_LOST                   34
-#define BRCMF_E_RESET_COMPLETE                 35
-#define BRCMF_E_JOIN_START                     36
-#define BRCMF_E_ROAM_START                     37
-#define BRCMF_E_ASSOC_START                    38
-#define BRCMF_E_IBSS_ASSOC                     39
-#define BRCMF_E_RADIO                          40
-#define BRCMF_E_PSM_WATCHDOG                   41
-#define BRCMF_E_PROBREQ_MSG                    44
-#define BRCMF_E_SCAN_CONFIRM_IND               45
-#define BRCMF_E_PSK_SUP                                46
-#define BRCMF_E_COUNTRY_CODE_CHANGED           47
-#define        BRCMF_E_EXCEEDED_MEDIUM_TIME            48
-#define BRCMF_E_ICV_ERROR                      49
-#define BRCMF_E_UNICAST_DECODE_ERROR           50
-#define BRCMF_E_MULTICAST_DECODE_ERROR         51
-#define BRCMF_E_TRACE                          52
-#define BRCMF_E_IF                             54
-#define BRCMF_E_RSSI                           56
-#define BRCMF_E_PFN_SCAN_COMPLETE              57
-#define BRCMF_E_EXTLOG_MSG                     58
-#define BRCMF_E_ACTION_FRAME                   59
-#define BRCMF_E_ACTION_FRAME_COMPLETE          60
-#define BRCMF_E_PRE_ASSOC_IND                  61
-#define BRCMF_E_PRE_REASSOC_IND                        62
-#define BRCMF_E_CHANNEL_ADOPTED                        63
-#define BRCMF_E_AP_STARTED                     64
-#define BRCMF_E_DFS_AP_STOP                    65
-#define BRCMF_E_DFS_AP_RESUME                  66
-#define BRCMF_E_RESERVED1                      67
-#define BRCMF_E_RESERVED2                      68
-#define BRCMF_E_ESCAN_RESULT                   69
-#define BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE 70
-#define BRCMF_E_DCS_REQUEST                    73
-
-#define BRCMF_E_FIFO_CREDIT_MAP                        74
-
-#define BRCMF_E_LAST                           75
-
 #define BRCMF_E_STATUS_SUCCESS                 0
 #define BRCMF_E_STATUS_FAIL                    1
 #define BRCMF_E_STATUS_TIMEOUT                 2
@@ -403,7 +283,7 @@ struct brcm_rateset_le {
        /* # rates in this set */
        __le32 count;
        /* rates in 500kbps units w/hi bit set if basic */
-       u8 rates[WL_NUMRATES];
+       u8 rates[BRCMF_MAXRATES_IN_SET];
 };
 
 struct brcmf_ssid {
@@ -452,14 +332,6 @@ struct brcmf_scan_params_le {
        __le16 channel_list[1]; /* list of chanspecs */
 };
 
-/* incremental scan struct */
-struct brcmf_iscan_params_le {
-       __le32 version;
-       __le16 action;
-       __le16 scan_duration;
-       struct brcmf_scan_params_le params_le;
-};
-
 struct brcmf_scan_results {
        u32 buflen;
        u32 version;
@@ -467,12 +339,6 @@ struct brcmf_scan_results {
        struct brcmf_bss_info_le bss_info_le[];
 };
 
-struct brcmf_scan_results_le {
-       __le32 buflen;
-       __le32 version;
-       __le32 count;
-};
-
 struct brcmf_escan_params_le {
        __le32 version;
        __le16 action;
@@ -508,23 +374,6 @@ struct brcmf_join_params {
        struct brcmf_assoc_params_le params_le;
 };
 
-/* incremental scan results struct */
-struct brcmf_iscan_results {
-       union {
-               u32 status;
-               __le32 status_le;
-       };
-       union {
-               struct brcmf_scan_results results;
-               struct brcmf_scan_results_le results_le;
-       };
-};
-
-/* size of brcmf_iscan_results not including variable length array */
-#define BRCMF_ISCAN_RESULTS_FIXED_SIZE \
-       (sizeof(struct brcmf_scan_results) + \
-        offsetof(struct brcmf_iscan_results, results))
-
 struct brcmf_wsec_key {
        u32 index;              /* key index */
        u32 len;                /* key length */
@@ -661,10 +510,11 @@ struct brcmf_pub {
        struct mutex proto_block;
        unsigned char proto_buf[BRCMF_DCMD_MAXLEN];
 
-       struct work_struct setmacaddr_work;
-       struct work_struct multicast_work;
        u8 macvalue[ETH_ALEN];
        atomic_t pend_8021x_cnt;
+       wait_queue_head_t pend_8021x_wait;
+
+       struct brcmf_fweh_info fweh;
 #ifdef DEBUG
        struct dentry *dbgfs_dir;
 #endif
@@ -701,6 +551,8 @@ struct brcmf_if {
        struct brcmf_cfg80211_vif *vif;
        struct net_device *ndev;
        struct net_device_stats stats;
+       struct work_struct setmacaddr_work;
+       struct work_struct multicast_work;
        int idx;
        s32 bssidx;
        u8 mac_addr[ETH_ALEN];
@@ -714,9 +566,6 @@ static inline s32 brcmf_ndev_bssidx(struct net_device *ndev)
 
 extern const struct bcmevent_name bcmevent_names[];
 
-extern uint brcmf_c_mkiovar(char *name, char *data, uint datalen,
-                         char *buf, uint len);
-
 extern int brcmf_netdev_wait_pend8021x(struct net_device *ndev);
 
 /* Return pointer to interface name */
@@ -728,14 +577,9 @@ extern int brcmf_proto_cdc_query_dcmd(struct brcmf_pub *drvr, int ifidx,
 extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx, uint cmd,
                                    void *buf, uint len);
 
-extern int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name);
-extern int brcmf_c_host_event(struct brcmf_pub *drvr, int *idx,
-                             void *pktdata, struct brcmf_event_msg *,
-                             void **data_ptr);
-
 extern int brcmf_net_attach(struct brcmf_if *ifp);
-extern struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
-                                    char *name, u8 *mac_addr);
+extern struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx,
+                                    s32 bssidx, char *name, u8 *mac_addr);
 extern void brcmf_del_if(struct brcmf_pub *drvr, int ifidx);
 
 #endif                         /* _BRCMF_H_ */
index 265580f5b27084a68d786a08e21760208159bad6..b8f248797f621f5a66062c9a0d8796e5def31edb 100644 (file)
@@ -45,7 +45,6 @@ struct brcmf_bus_dcmd {
 
 /* interface structure between common and bus layer */
 struct brcmf_bus {
-       u8 type;                /* bus type */
        union {
                struct brcmf_sdio_dev *sdio;
                struct brcmf_usbdev *usb;
@@ -85,7 +84,7 @@ extern 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. */
-extern void brcmf_rx_frame(struct device *dev, int ifidx,
+extern void brcmf_rx_frame(struct device *dev, u8 ifidx,
                           struct sk_buff_head *rxlist);
 static inline void brcmf_rx_packet(struct device *dev, int ifidx,
                                   struct sk_buff *pkt)
index b9d8a5adfd43bbda4a991e871210c240ab57b530..87536d38a4ca35b9fc05dc31efc00c5b477270a8 100644 (file)
@@ -23,8 +23,6 @@
 
 #include <linux/types.h>
 #include <linux/netdevice.h>
-#include <linux/sched.h>
-#include <defs.h>
 
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
@@ -277,76 +275,6 @@ done:
        return ret;
 }
 
-int
-brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx, struct brcmf_dcmd *dcmd,
-                 int len)
-{
-       struct brcmf_proto *prot = drvr->prot;
-       int ret = -1;
-
-       if (drvr->bus_if->state == BRCMF_BUS_DOWN) {
-               brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
-               return ret;
-       }
-       mutex_lock(&drvr->proto_block);
-
-       brcmf_dbg(TRACE, "Enter\n");
-
-       if (len > BRCMF_DCMD_MAXLEN)
-               goto done;
-
-       if (prot->pending == true) {
-               brcmf_dbg(TRACE, "CDC packet is pending!!!! cmd=0x%x (%lu) lastcmd=0x%x (%lu)\n",
-                         dcmd->cmd, (unsigned long)dcmd->cmd, prot->lastcmd,
-                         (unsigned long)prot->lastcmd);
-               if (dcmd->cmd == BRCMF_C_SET_VAR ||
-                   dcmd->cmd == BRCMF_C_GET_VAR)
-                       brcmf_dbg(TRACE, "iovar cmd=%s\n", (char *)dcmd->buf);
-
-               goto done;
-       }
-
-       prot->pending = true;
-       prot->lastcmd = dcmd->cmd;
-       if (dcmd->set)
-               ret = brcmf_proto_cdc_set_dcmd(drvr, ifidx, dcmd->cmd,
-                                                  dcmd->buf, len);
-       else {
-               ret = brcmf_proto_cdc_query_dcmd(drvr, ifidx, dcmd->cmd,
-                                                    dcmd->buf, len);
-               if (ret > 0)
-                       dcmd->used = ret -
-                                       sizeof(struct brcmf_proto_cdc_dcmd);
-       }
-
-       if (ret >= 0)
-               ret = 0;
-       else {
-               struct brcmf_proto_cdc_dcmd *msg = &prot->msg;
-               /* len == needed when set/query fails from dongle */
-               dcmd->needed = le32_to_cpu(msg->len);
-       }
-
-       /* Intercept the wme_dp dongle cmd here */
-       if (!ret && dcmd->cmd == BRCMF_C_SET_VAR &&
-           !strcmp(dcmd->buf, "wme_dp")) {
-               int slen;
-               __le32 val = 0;
-
-               slen = strlen("wme_dp") + 1;
-               if (len >= (int)(slen + sizeof(int)))
-                       memcpy(&val, (char *)dcmd->buf + slen, sizeof(int));
-               drvr->wme_dp = (u8) le32_to_cpu(val);
-       }
-
-       prot->pending = false;
-
-done:
-       mutex_unlock(&drvr->proto_block);
-
-       return ret;
-}
-
 static bool pkt_sum_needed(struct sk_buff *skb)
 {
        return skb->ip_summed == CHECKSUM_PARTIAL;
index 866b66995bb072a4f6dffe68f4ee269a299a91c8..eee7175f1515fdc674895923fc1e13554d389c99 100644 (file)
 
 #include <linux/kernel.h>
 #include <linux/string.h>
-#include <linux/sched.h>
 #include <linux/netdevice.h>
-#include <asm/unaligned.h>
-#include <defs.h>
 #include <brcmu_wifi.h>
 #include <brcmu_utils.h>
 #include "dhd.h"
@@ -30,9 +27,6 @@
 #include "dhd_dbg.h"
 #include "fwil.h"
 
-#define BRCM_OUI                       "\x00\x10\x18"
-#define DOT11_OUI_LEN                  3
-#define BCMILCP_BCM_SUBTYPE_EVENT      1
 #define PKTFILTER_BUF_SIZE             128
 #define BRCMF_ARPOL_MODE               0xb     /* agent|snoop|peer_autoreply */
 #define BRCMF_DEFAULT_BCN_TIMEOUT      3
 #define BRCMF_DEFAULT_SCAN_UNASSOC_TIME        40
 #define BRCMF_DEFAULT_PACKET_FILTER    "100 0 0 0 0x01 0x00"
 
-#define MSGTRACE_VERSION       1
-
-#define BRCMF_PKT_FILTER_FIXED_LEN     offsetof(struct brcmf_pkt_filter_le, u)
-#define BRCMF_PKT_FILTER_PATTERN_FIXED_LEN     \
-       offsetof(struct brcmf_pkt_filter_pattern_le, mask_and_pattern)
-
 #ifdef DEBUG
 static const char brcmf_version[] =
        "Dongle Host Driver, version " BRCMF_VERSION_STR "\nCompiled on "
@@ -55,43 +43,6 @@ static const char brcmf_version[] =
        "Dongle Host Driver, version " BRCMF_VERSION_STR;
 #endif
 
-/* Message trace header */
-struct msgtrace_hdr {
-       u8 version;
-       u8 spare;
-       __be16 len;             /* Len of the trace */
-       __be32 seqnum;          /* Sequence number of message. Useful
-                                * if the messsage has been lost
-                                * because of DMA error or a bus reset
-                                * (ex: SDIO Func2)
-                                */
-       __be32 discarded_bytes; /* Number of discarded bytes because of
-                                trace overflow  */
-       __be32 discarded_printf;        /* Number of discarded printf
-                                because of trace overflow */
-} __packed;
-
-
-uint
-brcmf_c_mkiovar(char *name, char *data, uint datalen, char *buf, uint buflen)
-{
-       uint len;
-
-       len = strlen(name) + 1;
-
-       if ((len + datalen) > buflen)
-               return 0;
-
-       strncpy(buf, name, buflen);
-
-       /* append data onto the end of the name string */
-       if (data && datalen) {
-               memcpy(&buf[len], data, datalen);
-               len += datalen;
-       }
-
-       return len;
-}
 
 bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
                      struct sk_buff *pkt, int prec)
@@ -143,405 +94,6 @@ bool brcmf_c_prec_enq(struct device *dev, struct pktq *q,
        return p != NULL;
 }
 
-#ifdef DEBUG
-static void
-brcmf_c_show_host_event(struct brcmf_event_msg *event, void *event_data)
-{
-       uint i, status, reason;
-       bool group = false, flush_txq = false, link = false;
-       char *auth_str, *event_name;
-       unsigned char *buf;
-       char err_msg[256], eabuf[ETHER_ADDR_STR_LEN];
-       static struct {
-               uint event;
-               char *event_name;
-       } event_names[] = {
-               {
-               BRCMF_E_SET_SSID, "SET_SSID"}, {
-               BRCMF_E_JOIN, "JOIN"}, {
-               BRCMF_E_START, "START"}, {
-               BRCMF_E_AUTH, "AUTH"}, {
-               BRCMF_E_AUTH_IND, "AUTH_IND"}, {
-               BRCMF_E_DEAUTH, "DEAUTH"}, {
-               BRCMF_E_DEAUTH_IND, "DEAUTH_IND"}, {
-               BRCMF_E_ASSOC, "ASSOC"}, {
-               BRCMF_E_ASSOC_IND, "ASSOC_IND"}, {
-               BRCMF_E_REASSOC, "REASSOC"}, {
-               BRCMF_E_REASSOC_IND, "REASSOC_IND"}, {
-               BRCMF_E_DISASSOC, "DISASSOC"}, {
-               BRCMF_E_DISASSOC_IND, "DISASSOC_IND"}, {
-               BRCMF_E_QUIET_START, "START_QUIET"}, {
-               BRCMF_E_QUIET_END, "END_QUIET"}, {
-               BRCMF_E_BEACON_RX, "BEACON_RX"}, {
-               BRCMF_E_LINK, "LINK"}, {
-               BRCMF_E_MIC_ERROR, "MIC_ERROR"}, {
-               BRCMF_E_NDIS_LINK, "NDIS_LINK"}, {
-               BRCMF_E_ROAM, "ROAM"}, {
-               BRCMF_E_TXFAIL, "TXFAIL"}, {
-               BRCMF_E_PMKID_CACHE, "PMKID_CACHE"}, {
-               BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF"}, {
-               BRCMF_E_PRUNE, "PRUNE"}, {
-               BRCMF_E_AUTOAUTH, "AUTOAUTH"}, {
-               BRCMF_E_EAPOL_MSG, "EAPOL_MSG"}, {
-               BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
-               BRCMF_E_ADDTS_IND, "ADDTS_IND"}, {
-               BRCMF_E_DELTS_IND, "DELTS_IND"}, {
-               BRCMF_E_BCNSENT_IND, "BCNSENT_IND"}, {
-               BRCMF_E_BCNRX_MSG, "BCNRX_MSG"}, {
-               BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG"}, {
-               BRCMF_E_ROAM_PREP, "ROAM_PREP"}, {
-               BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND"}, {
-               BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST"}, {
-               BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE"}, {
-               BRCMF_E_JOIN_START, "JOIN_START"}, {
-               BRCMF_E_ROAM_START, "ROAM_START"}, {
-               BRCMF_E_ASSOC_START, "ASSOC_START"}, {
-               BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC"}, {
-               BRCMF_E_RADIO, "RADIO"}, {
-               BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG"}, {
-               BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG"}, {
-               BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND"}, {
-               BRCMF_E_PSK_SUP, "PSK_SUP"}, {
-               BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED"}, {
-               BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME"}, {
-               BRCMF_E_ICV_ERROR, "ICV_ERROR"}, {
-               BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR"}, {
-               BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR"}, {
-               BRCMF_E_TRACE, "TRACE"}, {
-               BRCMF_E_ACTION_FRAME, "ACTION FRAME"}, {
-               BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION FRAME TX COMPLETE"}, {
-               BRCMF_E_IF, "IF"}, {
-               BRCMF_E_RSSI, "RSSI"}, {
-               BRCMF_E_PFN_SCAN_COMPLETE, "SCAN_COMPLETE"}, {
-               BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT"}
-       };
-       uint event_type, flags, auth_type, datalen;
-       static u32 seqnum_prev;
-       struct msgtrace_hdr hdr;
-       u32 nblost;
-       char *s, *p;
-
-       event_type = be32_to_cpu(event->event_type);
-       flags = be16_to_cpu(event->flags);
-       status = be32_to_cpu(event->status);
-       reason = be32_to_cpu(event->reason);
-       auth_type = be32_to_cpu(event->auth_type);
-       datalen = be32_to_cpu(event->datalen);
-       /* debug dump of event messages */
-       sprintf(eabuf, "%pM", event->addr);
-
-       event_name = "UNKNOWN";
-       for (i = 0; i < ARRAY_SIZE(event_names); i++) {
-               if (event_names[i].event == event_type)
-                       event_name = event_names[i].event_name;
-       }
-
-       brcmf_dbg(EVENT, "EVENT: %s, event ID = %d\n", event_name, event_type);
-       brcmf_dbg(EVENT, "flags 0x%04x, status %d, reason %d, auth_type %d MAC %s\n",
-                 flags, status, reason, auth_type, eabuf);
-
-       if (flags & BRCMF_EVENT_MSG_LINK)
-               link = true;
-       if (flags & BRCMF_EVENT_MSG_GROUP)
-               group = true;
-       if (flags & BRCMF_EVENT_MSG_FLUSHTXQ)
-               flush_txq = true;
-
-       switch (event_type) {
-       case BRCMF_E_START:
-       case BRCMF_E_DEAUTH:
-       case BRCMF_E_DISASSOC:
-               brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
-               break;
-
-       case BRCMF_E_ASSOC_IND:
-       case BRCMF_E_REASSOC_IND:
-               brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
-               break;
-
-       case BRCMF_E_ASSOC:
-       case BRCMF_E_REASSOC:
-               if (status == BRCMF_E_STATUS_SUCCESS)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, SUCCESS\n",
-                                 event_name, eabuf);
-               else if (status == BRCMF_E_STATUS_TIMEOUT)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, TIMEOUT\n",
-                                 event_name, eabuf);
-               else if (status == BRCMF_E_STATUS_FAIL)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, FAILURE, reason %d\n",
-                                 event_name, eabuf, (int)reason);
-               else
-                       brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, unexpected status %d\n",
-                                 event_name, eabuf, (int)status);
-               break;
-
-       case BRCMF_E_DEAUTH_IND:
-       case BRCMF_E_DISASSOC_IND:
-               brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, reason %d\n",
-                         event_name, eabuf, (int)reason);
-               break;
-
-       case BRCMF_E_AUTH:
-       case BRCMF_E_AUTH_IND:
-               if (auth_type == WLAN_AUTH_OPEN)
-                       auth_str = "Open System";
-               else if (auth_type == WLAN_AUTH_SHARED_KEY)
-                       auth_str = "Shared Key";
-               else {
-                       sprintf(err_msg, "AUTH unknown: %d", (int)auth_type);
-                       auth_str = err_msg;
-               }
-               if (event_type == BRCMF_E_AUTH_IND)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s\n",
-                                 event_name, eabuf, auth_str);
-               else if (status == BRCMF_E_STATUS_SUCCESS)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, SUCCESS\n",
-                                 event_name, eabuf, auth_str);
-               else if (status == BRCMF_E_STATUS_TIMEOUT)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, TIMEOUT\n",
-                                 event_name, eabuf, auth_str);
-               else if (status == BRCMF_E_STATUS_FAIL) {
-                       brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, %s, FAILURE, reason %d\n",
-                                 event_name, eabuf, auth_str, (int)reason);
-               }
-
-               break;
-
-       case BRCMF_E_JOIN:
-       case BRCMF_E_ROAM:
-       case BRCMF_E_SET_SSID:
-               if (status == BRCMF_E_STATUS_SUCCESS)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n",
-                                 event_name, eabuf);
-               else if (status == BRCMF_E_STATUS_FAIL)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, failed\n", event_name);
-               else if (status == BRCMF_E_STATUS_NO_NETWORKS)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, no networks found\n",
-                                 event_name);
-               else
-                       brcmf_dbg(EVENT, "MACEVENT: %s, unexpected status %d\n",
-                                 event_name, (int)status);
-               break;
-
-       case BRCMF_E_BEACON_RX:
-               if (status == BRCMF_E_STATUS_SUCCESS)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, SUCCESS\n", event_name);
-               else if (status == BRCMF_E_STATUS_FAIL)
-                       brcmf_dbg(EVENT, "MACEVENT: %s, FAIL\n", event_name);
-               else
-                       brcmf_dbg(EVENT, "MACEVENT: %s, status %d\n",
-                                 event_name, status);
-               break;
-
-       case BRCMF_E_LINK:
-               brcmf_dbg(EVENT, "MACEVENT: %s %s\n",
-                         event_name, link ? "UP" : "DOWN");
-               break;
-
-       case BRCMF_E_MIC_ERROR:
-               brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s, Group %d, Flush %d\n",
-                         event_name, eabuf, group, flush_txq);
-               break;
-
-       case BRCMF_E_ICV_ERROR:
-       case BRCMF_E_UNICAST_DECODE_ERROR:
-       case BRCMF_E_MULTICAST_DECODE_ERROR:
-               brcmf_dbg(EVENT, "MACEVENT: %s, MAC %s\n", event_name, eabuf);
-               break;
-
-       case BRCMF_E_TXFAIL:
-               brcmf_dbg(EVENT, "MACEVENT: %s, RA %s\n", event_name, eabuf);
-               break;
-
-       case BRCMF_E_SCAN_COMPLETE:
-       case BRCMF_E_PMKID_CACHE:
-               brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
-               break;
-
-       case BRCMF_E_ESCAN_RESULT:
-               brcmf_dbg(EVENT, "MACEVENT: %s\n", event_name);
-               datalen = 0;
-               break;
-
-       case BRCMF_E_PFN_NET_FOUND:
-       case BRCMF_E_PFN_NET_LOST:
-       case BRCMF_E_PFN_SCAN_COMPLETE:
-               brcmf_dbg(EVENT, "PNOEVENT: %s\n", event_name);
-               break;
-
-       case BRCMF_E_PSK_SUP:
-       case BRCMF_E_PRUNE:
-               brcmf_dbg(EVENT, "MACEVENT: %s, status %d, reason %d\n",
-                         event_name, (int)status, (int)reason);
-               break;
-
-       case BRCMF_E_TRACE:
-               buf = (unsigned char *) event_data;
-               memcpy(&hdr, buf, sizeof(struct msgtrace_hdr));
-
-               if (hdr.version != MSGTRACE_VERSION) {
-                       brcmf_dbg(ERROR,
-                                 "MACEVENT: %s [unsupported version --> brcmf"
-                                 " version:%d dongle version:%d]\n",
-                                 event_name, MSGTRACE_VERSION, hdr.version);
-                       /* Reset datalen to avoid display below */
-                       datalen = 0;
-                       break;
-               }
-
-               /* There are 2 bytes available at the end of data */
-               *(buf + sizeof(struct msgtrace_hdr)
-                        + be16_to_cpu(hdr.len)) = '\0';
-
-               if (be32_to_cpu(hdr.discarded_bytes)
-                   || be32_to_cpu(hdr.discarded_printf))
-                       brcmf_dbg(ERROR,
-                                 "WLC_E_TRACE: [Discarded traces in dongle -->"
-                                 " discarded_bytes %d discarded_printf %d]\n",
-                                 be32_to_cpu(hdr.discarded_bytes),
-                                 be32_to_cpu(hdr.discarded_printf));
-
-               nblost = be32_to_cpu(hdr.seqnum) - seqnum_prev - 1;
-               if (nblost > 0)
-                       brcmf_dbg(ERROR, "WLC_E_TRACE: [Event lost --> seqnum "
-                                 " %d nblost %d\n", be32_to_cpu(hdr.seqnum),
-                                 nblost);
-               seqnum_prev = be32_to_cpu(hdr.seqnum);
-
-               /* Display the trace buffer. Advance from \n to \n to
-                * avoid display big
-                * printf (issue with Linux printk )
-                */
-               p = (char *)&buf[sizeof(struct msgtrace_hdr)];
-               while ((s = strstr(p, "\n")) != NULL) {
-                       *s = '\0';
-                       pr_debug("%s\n", p);
-                       p = s + 1;
-               }
-               pr_debug("%s\n", p);
-
-               /* Reset datalen to avoid display below */
-               datalen = 0;
-               break;
-
-       case BRCMF_E_RSSI:
-               brcmf_dbg(EVENT, "MACEVENT: %s %d\n",
-                         event_name, be32_to_cpu(*((__be32 *)event_data)));
-               break;
-
-       default:
-               brcmf_dbg(EVENT,
-                         "MACEVENT: %s %d, MAC %s, status %d, reason %d, "
-                         "auth %d\n", event_name, event_type, eabuf,
-                         (int)status, (int)reason, (int)auth_type);
-               break;
-       }
-
-       /* show any appended data */
-       brcmf_dbg_hex_dump(datalen, event_data, datalen, "Received data");
-}
-#endif                         /* DEBUG */
-
-int
-brcmf_c_host_event(struct brcmf_pub *drvr, int *ifidx, void *pktdata,
-                  struct brcmf_event_msg *event, void **data_ptr)
-{
-       /* check whether packet is a BRCM event pkt */
-       struct brcmf_event *pvt_data = (struct brcmf_event *) pktdata;
-       struct brcmf_if_event *ifevent;
-       struct brcmf_if *ifp;
-       char *event_data;
-       u32 type, status;
-       u16 flags;
-       int evlen;
-
-       if (memcmp(BRCM_OUI, &pvt_data->hdr.oui[0], DOT11_OUI_LEN)) {
-               brcmf_dbg(ERROR, "mismatched OUI, bailing\n");
-               return -EBADE;
-       }
-
-       /* BRCM event pkt may be unaligned - use xxx_ua to load user_subtype. */
-       if (get_unaligned_be16(&pvt_data->hdr.usr_subtype) !=
-           BCMILCP_BCM_SUBTYPE_EVENT) {
-               brcmf_dbg(ERROR, "mismatched subtype, bailing\n");
-               return -EBADE;
-       }
-
-       *data_ptr = &pvt_data[1];
-       event_data = *data_ptr;
-
-       /* memcpy since BRCM event pkt may be unaligned. */
-       memcpy(event, &pvt_data->msg, sizeof(struct brcmf_event_msg));
-
-       type = get_unaligned_be32(&event->event_type);
-       flags = get_unaligned_be16(&event->flags);
-       status = get_unaligned_be32(&event->status);
-       evlen = get_unaligned_be32(&event->datalen) +
-               sizeof(struct brcmf_event);
-
-       switch (type) {
-       case BRCMF_E_IF:
-               ifevent = (struct brcmf_if_event *) event_data;
-               brcmf_dbg(TRACE, "if event\n");
-
-               if (ifevent->ifidx > 0 && ifevent->ifidx < BRCMF_MAX_IFS) {
-                       if (ifevent->action == BRCMF_E_IF_ADD) {
-                               ifp = brcmf_add_if(drvr->dev, ifevent->ifidx,
-                                                  ifevent->bssidx,
-                                                  event->ifname,
-                                                  pvt_data->eth.h_dest);
-                               if (IS_ERR(ifp))
-                                       return PTR_ERR(ifp);
-                               brcmf_net_attach(ifp);
-                       } else {
-                               brcmf_del_if(drvr, ifevent->ifidx);
-                       }
-               } else {
-                       brcmf_dbg(ERROR, "Invalid ifidx %d for %s\n",
-                                 ifevent->ifidx, event->ifname);
-               }
-
-               /* send up the if event: btamp user needs it */
-               *ifidx = brcmf_ifname2idx(drvr, event->ifname);
-               break;
-
-               /* These are what external supplicant/authenticator wants */
-       case BRCMF_E_LINK:
-       case BRCMF_E_ASSOC_IND:
-       case BRCMF_E_REASSOC_IND:
-       case BRCMF_E_DISASSOC_IND:
-       case BRCMF_E_MIC_ERROR:
-       default:
-               /* Fall through: this should get _everything_  */
-
-               *ifidx = brcmf_ifname2idx(drvr, event->ifname);
-               brcmf_dbg(TRACE, "MAC event %d, flags %x, status %x\n",
-                         type, flags, status);
-
-               /* put it back to BRCMF_E_NDIS_LINK */
-               if (type == BRCMF_E_NDIS_LINK) {
-                       u32 temp1;
-                       __be32 temp2;
-
-                       temp1 = get_unaligned_be32(&event->event_type);
-                       brcmf_dbg(TRACE, "Converted to WLC_E_LINK type %d\n",
-                                 temp1);
-
-                       temp2 = cpu_to_be32(BRCMF_E_NDIS_LINK);
-                       memcpy((void *)(&pvt_data->msg.event_type), &temp2,
-                              sizeof(pvt_data->msg.event_type));
-               }
-               break;
-       }
-
-#ifdef DEBUG
-       if (BRCMF_EVENT_ON())
-               brcmf_c_show_host_event(event, event_data);
-#endif /* DEBUG */
-
-       return 0;
-}
-
 /* Convert user's input in hex pattern to byte-size mask */
 static int brcmf_c_pattern_atoh(char *src, char *dst)
 {
@@ -686,8 +238,8 @@ static void brcmf_c_pktfilter_offload_set(struct brcmf_if *ifp, char *arg)
        }
 
        pkt_filter->u.pattern.size_bytes = cpu_to_le32(mask_size);
-       buf_len = sizeof(*pkt_filter);
-       buf_len -= sizeof(pkt_filter->u.pattern.mask_and_pattern);
+       buf_len = offsetof(struct brcmf_pkt_filter_le,
+                          u.pattern.mask_and_pattern);
        buf_len += mask_size + pattern_size;
 
        err = brcmf_fil_iovar_data_set(ifp, "pkt_filter_add", pkt_filter,
index 862d2acb7a1670ce9edca882ac647cf7c00a7aac..7e58e8ce9aba68981e0590f7c34f11d8ae3459d9 100644 (file)
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 #include <linux/debugfs.h>
-#include <linux/if_ether.h>
-#include <linux/if.h>
 #include <linux/netdevice.h>
-#include <linux/ieee80211.h>
 #include <linux/module.h>
-#include <linux/netdevice.h>
 
-#include <defs.h>
 #include <brcmu_wifi.h>
 #include <brcmu_utils.h>
 #include "dhd.h"
-#include "dhd_bus.h"
 #include "dhd_dbg.h"
 
 static struct dentry *root_folder;
index eefa6c2560cc87f9f917ffcc95711b9d5a7b6e87..a0e18a1ceb4b066942c84e8ec9da0b0ad48503b3 100644 (file)
 #define BRCMF_HDRS_VAL 0x0040
 #define BRCMF_BYTES_VAL        0x0080
 #define BRCMF_INTR_VAL 0x0100
-#define BRCMF_GLOM_VAL 0x0400
-#define BRCMF_EVENT_VAL        0x0800
-#define BRCMF_BTA_VAL  0x1000
-#define BRCMF_ISCAN_VAL 0x2000
-#define BRCMF_FIL_VAL  0x4000
+#define BRCMF_GLOM_VAL 0x0200
+#define BRCMF_EVENT_VAL        0x0400
+#define BRCMF_BTA_VAL  0x0800
+#define BRCMF_FIL_VAL  0x1000
+#define BRCMF_USB_VAL  0x2000
 
 #if defined(DEBUG)
 
index 297652339fda9364d80e2078aae10d40aa22a00e..b6c86b046c15df2ff502aec761347bbf4bc5bd4b 100644 (file)
 
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
-#include <linux/init.h>
 #include <linux/kernel.h>
-#include <linux/kthread.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
 #include <linux/etherdevice.h>
-#include <linux/mmc/sdio_func.h>
-#include <linux/random.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/fcntl.h>
-#include <linux/fs.h>
-#include <linux/uaccess.h>
-#include <linux/hardirq.h>
-#include <linux/mutex.h>
-#include <linux/wait.h>
 #include <linux/module.h>
 #include <net/cfg80211.h>
 #include <net/rtnetlink.h>
-#include <defs.h>
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 
 #include "dhd_proto.h"
 #include "dhd_dbg.h"
 #include "wl_cfg80211.h"
+#include "fwil.h"
 
 MODULE_AUTHOR("Broadcom Corporation");
-MODULE_DESCRIPTION("Broadcom 802.11n wireless LAN fullmac driver.");
-MODULE_SUPPORTED_DEVICE("Broadcom 802.11n WLAN fullmac cards");
+MODULE_DESCRIPTION("Broadcom 802.11 wireless LAN fullmac driver.");
+MODULE_SUPPORTED_DEVICE("Broadcom 802.11 WLAN fullmac cards");
 MODULE_LICENSE("Dual BSD/GPL");
 
+#define MAX_WAIT_FOR_8021X_TX          50      /* msecs */
 
 /* Error bits */
 int brcmf_msg_level = BRCMF_ERROR_VAL;
 module_param(brcmf_msg_level, int, 0);
 
-int brcmf_ifname2idx(struct brcmf_pub *drvr, char *name)
-{
-       int i = BRCMF_MAX_IFS;
-       struct brcmf_if *ifp;
-
-       if (name == NULL || *name == '\0')
-               return 0;
-
-       while (--i > 0) {
-               ifp = drvr->iflist[i];
-               if (ifp && !strncmp(ifp->ndev->name, name, IFNAMSIZ))
-                       break;
-       }
-
-       brcmf_dbg(TRACE, "return idx %d for \"%s\"\n", i, name);
-
-       return i;               /* default - the primary interface */
-}
 
 char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
 {
@@ -95,38 +63,33 @@ char *brcmf_ifname(struct brcmf_pub *drvr, int ifidx)
 
 static void _brcmf_set_multicast_list(struct work_struct *work)
 {
+       struct brcmf_if *ifp;
        struct net_device *ndev;
        struct netdev_hw_addr *ha;
-       u32 dcmd_value, cnt;
+       u32 cmd_value, cnt;
        __le32 cnt_le;
-       __le32 dcmd_le_value;
-
-       struct brcmf_dcmd dcmd;
        char *buf, *bufp;
-       uint buflen;
-       int ret;
+       u32 buflen;
+       s32 err;
 
-       struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
-                                                   multicast_work);
+       brcmf_dbg(TRACE, "enter\n");
 
-       ndev = drvr->iflist[0]->ndev;
-       cnt = netdev_mc_count(ndev);
+       ifp = container_of(work, struct brcmf_if, multicast_work);
+       ndev = ifp->ndev;
 
        /* Determine initial value of allmulti flag */
-       dcmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
+       cmd_value = (ndev->flags & IFF_ALLMULTI) ? true : false;
 
        /* Send down the multicast list first. */
-
-       buflen = sizeof("mcast_list") + sizeof(cnt) + (cnt * ETH_ALEN);
-       bufp = buf = kmalloc(buflen, GFP_ATOMIC);
-       if (!bufp)
+       cnt = netdev_mc_count(ndev);
+       buflen = sizeof(cnt) + (cnt * ETH_ALEN);
+       buf = kmalloc(buflen, GFP_ATOMIC);
+       if (!buf)
                return;
-
-       strcpy(bufp, "mcast_list");
-       bufp += strlen("mcast_list") + 1;
+       bufp = buf;
 
        cnt_le = cpu_to_le32(cnt);
-       memcpy(bufp, &cnt_le, sizeof(cnt));
+       memcpy(bufp, &cnt_le, sizeof(cnt_le));
        bufp += sizeof(cnt_le);
 
        netdev_for_each_mc_addr(ha, ndev) {
@@ -137,129 +100,66 @@ static void _brcmf_set_multicast_list(struct work_struct *work)
                cnt--;
        }
 
-       memset(&dcmd, 0, sizeof(dcmd));
-       dcmd.cmd = BRCMF_C_SET_VAR;
-       dcmd.buf = buf;
-       dcmd.len = buflen;
-       dcmd.set = true;
-
-       ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
-       if (ret < 0) {
-               brcmf_dbg(ERROR, "%s: set mcast_list failed, cnt %d\n",
-                         brcmf_ifname(drvr, 0), cnt);
-               dcmd_value = cnt ? true : dcmd_value;
+       err = brcmf_fil_iovar_data_set(ifp, "mcast_list", buf, buflen);
+       if (err < 0) {
+               brcmf_dbg(ERROR, "Setting mcast_list failed, %d\n", err);
+               cmd_value = cnt ? true : cmd_value;
        }
 
        kfree(buf);
 
-       /* Now send the allmulti setting.  This is based on the setting in the
+       /*
+        * Now send the allmulti setting.  This is based on the setting in the
         * net_device flags, but might be modified above to be turned on if we
         * were trying to set some addresses and dongle rejected it...
         */
-
-       buflen = sizeof("allmulti") + sizeof(dcmd_value);
-       buf = kmalloc(buflen, GFP_ATOMIC);
-       if (!buf)
-               return;
-
-       dcmd_le_value = cpu_to_le32(dcmd_value);
-
-       if (!brcmf_c_mkiovar
-           ("allmulti", (void *)&dcmd_le_value,
-           sizeof(dcmd_le_value), buf, buflen)) {
-               brcmf_dbg(ERROR, "%s: mkiovar failed for allmulti, datalen %d buflen %u\n",
-                         brcmf_ifname(drvr, 0),
-                         (int)sizeof(dcmd_value), buflen);
-               kfree(buf);
-               return;
-       }
-
-       memset(&dcmd, 0, sizeof(dcmd));
-       dcmd.cmd = BRCMF_C_SET_VAR;
-       dcmd.buf = buf;
-       dcmd.len = buflen;
-       dcmd.set = true;
-
-       ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
-       if (ret < 0) {
-               brcmf_dbg(ERROR, "%s: set allmulti %d failed\n",
-                         brcmf_ifname(drvr, 0),
-                         le32_to_cpu(dcmd_le_value));
-       }
-
-       kfree(buf);
-
-       /* Finally, pick up the PROMISC flag as well, like the NIC
-                driver does */
-
-       dcmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
-       dcmd_le_value = cpu_to_le32(dcmd_value);
-
-       memset(&dcmd, 0, sizeof(dcmd));
-       dcmd.cmd = BRCMF_C_SET_PROMISC;
-       dcmd.buf = &dcmd_le_value;
-       dcmd.len = sizeof(dcmd_le_value);
-       dcmd.set = true;
-
-       ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
-       if (ret < 0) {
-               brcmf_dbg(ERROR, "%s: set promisc %d failed\n",
-                         brcmf_ifname(drvr, 0),
-                         le32_to_cpu(dcmd_le_value));
-       }
+       err = brcmf_fil_iovar_int_set(ifp, "allmulti", cmd_value);
+       if (err < 0)
+               brcmf_dbg(ERROR, "Setting allmulti failed, %d\n", err);
+
+       /*Finally, pick up the PROMISC flag */
+       cmd_value = (ndev->flags & IFF_PROMISC) ? true : false;
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PROMISC, cmd_value);
+       if (err < 0)
+               brcmf_dbg(ERROR, "Setting BRCMF_C_SET_PROMISC failed, %d\n",
+                         err);
 }
 
 static void
 _brcmf_set_mac_address(struct work_struct *work)
 {
-       char buf[32];
-       struct brcmf_dcmd dcmd;
-       int ret;
-
-       struct brcmf_pub *drvr = container_of(work, struct brcmf_pub,
-                                                   setmacaddr_work);
+       struct brcmf_if *ifp;
+       s32 err;
 
        brcmf_dbg(TRACE, "enter\n");
-       if (!brcmf_c_mkiovar("cur_etheraddr", (char *)drvr->macvalue,
-                          ETH_ALEN, buf, 32)) {
-               brcmf_dbg(ERROR, "%s: mkiovar failed for cur_etheraddr\n",
-                         brcmf_ifname(drvr, 0));
-               return;
-       }
-       memset(&dcmd, 0, sizeof(dcmd));
-       dcmd.cmd = BRCMF_C_SET_VAR;
-       dcmd.buf = buf;
-       dcmd.len = 32;
-       dcmd.set = true;
 
-       ret = brcmf_proto_dcmd(drvr, 0, &dcmd, dcmd.len);
-       if (ret < 0)
-               brcmf_dbg(ERROR, "%s: set cur_etheraddr failed\n",
-                         brcmf_ifname(drvr, 0));
-       else
-               memcpy(drvr->iflist[0]->ndev->dev_addr,
-                      drvr->macvalue, ETH_ALEN);
-
-       return;
+       ifp = container_of(work, struct brcmf_if, setmacaddr_work);
+       err = brcmf_fil_iovar_data_set(ifp, "cur_etheraddr", ifp->mac_addr,
+                                      ETH_ALEN);
+       if (err < 0) {
+               brcmf_dbg(ERROR, "Setting cur_etheraddr failed, %d\n", err);
+       } else {
+               brcmf_dbg(TRACE, "MAC address updated to %pM\n",
+                         ifp->mac_addr);
+               memcpy(ifp->ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
+       }
 }
 
 static int brcmf_netdev_set_mac_address(struct net_device *ndev, void *addr)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_pub *drvr = ifp->drvr;
        struct sockaddr *sa = (struct sockaddr *)addr;
 
-       memcpy(&drvr->macvalue, sa->sa_data, ETH_ALEN);
-       schedule_work(&drvr->setmacaddr_work);
+       memcpy(&ifp->mac_addr, sa->sa_data, ETH_ALEN);
+       schedule_work(&ifp->setmacaddr_work);
        return 0;
 }
 
 static void brcmf_netdev_set_multicast_list(struct net_device *ndev)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_pub *drvr = ifp->drvr;
 
-       schedule_work(&drvr->multicast_work);
+       schedule_work(&ifp->multicast_work);
 }
 
 static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
@@ -272,7 +172,7 @@ static int brcmf_netdev_start_xmit(struct sk_buff *skb, struct net_device *ndev)
 
        /* Reject if down */
        if (!drvr->bus_if->drvr_up ||
-           (drvr->bus_if->state == BRCMF_BUS_DOWN)) {
+           (drvr->bus_if->state != BRCMF_BUS_DATA)) {
                brcmf_dbg(ERROR, "xmit rejected drvup=%d state=%d\n",
                          drvr->bus_if->drvr_up,
                          drvr->bus_if->state);
@@ -350,32 +250,13 @@ void brcmf_txflowblock(struct device *dev, bool state)
                }
 }
 
-static int brcmf_host_event(struct brcmf_pub *drvr, int *ifidx,
-                           void *pktdata, struct brcmf_event_msg *event,
-                           void **data)
-{
-       int bcmerror = 0;
-
-       bcmerror = brcmf_c_host_event(drvr, ifidx, pktdata, event, data);
-       if (bcmerror != 0)
-               return bcmerror;
-
-       if (drvr->iflist[*ifidx]->ndev)
-               brcmf_cfg80211_event(drvr->iflist[*ifidx]->ndev,
-                                    event, *data);
-
-       return bcmerror;
-}
-
-void brcmf_rx_frame(struct device *dev, int ifidx,
+void brcmf_rx_frame(struct device *dev, u8 ifidx,
                    struct sk_buff_head *skb_list)
 {
        unsigned char *eth;
        uint len;
-       void *data;
        struct sk_buff *skb, *pnext;
        struct brcmf_if *ifp;
-       struct brcmf_event_msg event;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_pub *drvr = bus_if->drvr;
 
@@ -422,10 +303,7 @@ void brcmf_rx_frame(struct device *dev, int ifidx,
                skb_pull(skb, ETH_HLEN);
 
                /* Process special event packets and then discard them */
-               if (ntohs(skb->protocol) == ETH_P_LINK_CTL)
-                       brcmf_host_event(drvr, &ifidx,
-                                         skb_mac_header(skb),
-                                         &event, &data);
+               brcmf_fweh_process_skb(drvr, skb, &ifidx);
 
                if (drvr->iflist[ifidx]) {
                        ifp = drvr->iflist[ifidx];
@@ -461,9 +339,11 @@ void brcmf_txcomplete(struct device *dev, struct sk_buff *txp, bool success)
        eh = (struct ethhdr *)(txp->data);
        type = ntohs(eh->h_proto);
 
-       if (type == ETH_P_PAE)
+       if (type == ETH_P_PAE) {
                atomic_dec(&drvr->pend_8021x_cnt);
-
+               if (waitqueue_active(&drvr->pend_8021x_wait))
+                       wake_up(&drvr->pend_8021x_wait);
+       }
 }
 
 static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
@@ -487,83 +367,26 @@ static struct net_device_stats *brcmf_netdev_get_stats(struct net_device *ndev)
        return &ifp->stats;
 }
 
-/* Retrieve current toe component enables, which are kept
-        as a bitmap in toe_ol iovar */
-static int brcmf_toe_get(struct brcmf_pub *drvr, int ifidx, u32 *toe_ol)
-{
-       struct brcmf_dcmd dcmd;
-       __le32 toe_le;
-       char buf[32];
-       int ret;
-
-       memset(&dcmd, 0, sizeof(dcmd));
-
-       dcmd.cmd = BRCMF_C_GET_VAR;
-       dcmd.buf = buf;
-       dcmd.len = (uint) sizeof(buf);
-       dcmd.set = false;
-
-       strcpy(buf, "toe_ol");
-       ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
-       if (ret < 0) {
-               /* Check for older dongle image that doesn't support toe_ol */
-               if (ret == -EIO) {
-                       brcmf_dbg(ERROR, "%s: toe not supported by device\n",
-                                 brcmf_ifname(drvr, ifidx));
-                       return -EOPNOTSUPP;
-               }
-
-               brcmf_dbg(INFO, "%s: could not get toe_ol: ret=%d\n",
-                         brcmf_ifname(drvr, ifidx), ret);
-               return ret;
-       }
-
-       memcpy(&toe_le, buf, sizeof(u32));
-       *toe_ol = le32_to_cpu(toe_le);
-       return 0;
-}
-
-/* Set current toe component enables in toe_ol iovar,
-        and set toe global enable iovar */
-static int brcmf_toe_set(struct brcmf_pub *drvr, int ifidx, u32 toe_ol)
+/*
+ * Set current toe component enables in toe_ol iovar,
+ * and set toe global enable iovar
+ */
+static int brcmf_toe_set(struct brcmf_if *ifp, u32 toe_ol)
 {
-       struct brcmf_dcmd dcmd;
-       char buf[32];
-       int ret;
-       __le32 toe_le = cpu_to_le32(toe_ol);
-
-       memset(&dcmd, 0, sizeof(dcmd));
+       s32 err;
 
-       dcmd.cmd = BRCMF_C_SET_VAR;
-       dcmd.buf = buf;
-       dcmd.len = (uint) sizeof(buf);
-       dcmd.set = true;
-
-       /* Set toe_ol as requested */
-       strcpy(buf, "toe_ol");
-       memcpy(&buf[sizeof("toe_ol")], &toe_le, sizeof(u32));
-
-       ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
-       if (ret < 0) {
-               brcmf_dbg(ERROR, "%s: could not set toe_ol: ret=%d\n",
-                         brcmf_ifname(drvr, ifidx), ret);
-               return ret;
+       err = brcmf_fil_iovar_int_set(ifp, "toe_ol", toe_ol);
+       if (err < 0) {
+               brcmf_dbg(ERROR, "Setting toe_ol failed, %d\n", err);
+               return err;
        }
 
-       /* Enable toe globally only if any components are enabled. */
-       toe_le = cpu_to_le32(toe_ol != 0);
+       err = brcmf_fil_iovar_int_set(ifp, "toe", (toe_ol != 0));
+       if (err < 0)
+               brcmf_dbg(ERROR, "Setting toe failed, %d\n", err);
 
-       strcpy(buf, "toe");
-       memcpy(&buf[sizeof("toe")], &toe_le, sizeof(u32));
+       return err;
 
-       ret = brcmf_proto_dcmd(drvr, ifidx, &dcmd, dcmd.len);
-       if (ret < 0) {
-               brcmf_dbg(ERROR, "%s: could not set toe: ret=%d\n",
-                         brcmf_ifname(drvr, ifidx), ret);
-               return ret;
-       }
-
-       return 0;
 }
 
 static void brcmf_ethtool_get_drvinfo(struct net_device *ndev,
@@ -581,8 +404,9 @@ static const struct ethtool_ops brcmf_ethtool_ops = {
        .get_drvinfo = brcmf_ethtool_get_drvinfo,
 };
 
-static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
+static int brcmf_ethtool(struct brcmf_if *ifp, void __user *uaddr)
 {
+       struct brcmf_pub *drvr = ifp->drvr;
        struct ethtool_drvinfo info;
        char drvname[sizeof(info.driver)];
        u32 cmd;
@@ -633,7 +457,7 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
                /* Get toe offload components from dongle */
        case ETHTOOL_GRXCSUM:
        case ETHTOOL_GTXCSUM:
-               ret = brcmf_toe_get(drvr, 0, &toe_cmpnt);
+               ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
                if (ret < 0)
                        return ret;
 
@@ -654,7 +478,7 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
                        return -EFAULT;
 
                /* Read the current settings, update and write back */
-               ret = brcmf_toe_get(drvr, 0, &toe_cmpnt);
+               ret = brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_cmpnt);
                if (ret < 0)
                        return ret;
 
@@ -666,18 +490,16 @@ static int brcmf_ethtool(struct brcmf_pub *drvr, void __user *uaddr)
                else
                        toe_cmpnt &= ~csum_dir;
 
-               ret = brcmf_toe_set(drvr, 0, toe_cmpnt);
+               ret = brcmf_toe_set(ifp, toe_cmpnt);
                if (ret < 0)
                        return ret;
 
                /* If setting TX checksum mode, tell Linux the new mode */
                if (cmd == ETHTOOL_STXCSUM) {
                        if (edata.data)
-                               drvr->iflist[0]->ndev->features |=
-                                   NETIF_F_IP_CSUM;
+                               ifp->ndev->features |= NETIF_F_IP_CSUM;
                        else
-                               drvr->iflist[0]->ndev->features &=
-                                   ~NETIF_F_IP_CSUM;
+                               ifp->ndev->features &= ~NETIF_F_IP_CSUM;
                }
 
                break;
@@ -701,7 +523,7 @@ static int brcmf_netdev_ioctl_entry(struct net_device *ndev, struct ifreq *ifr,
                return -1;
 
        if (cmd == SIOCETHTOOL)
-               return brcmf_ethtool(drvr, ifr->ifr_data);
+               return brcmf_ethtool(ifp, ifr->ifr_data);
 
        return -EOPNOTSUPP;
 }
@@ -712,10 +534,12 @@ static int brcmf_netdev_stop(struct net_device *ndev)
        struct brcmf_pub *drvr = ifp->drvr;
 
        brcmf_dbg(TRACE, "Enter\n");
-       brcmf_cfg80211_down(drvr->config);
+
        if (drvr->bus_if->drvr_up == 0)
                return 0;
 
+       brcmf_cfg80211_down(ndev);
+
        /* Set state and stop OS transmissions */
        drvr->bus_if->drvr_up = false;
        netif_stop_queue(ndev);
@@ -730,38 +554,35 @@ static int brcmf_netdev_open(struct net_device *ndev)
        struct brcmf_bus *bus_if = drvr->bus_if;
        u32 toe_ol;
        s32 ret = 0;
-       uint up = 0;
 
        brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
 
-       if (ifp->idx == 0) {    /* do it only for primary eth0 */
-               /* If bus is not ready, can't continue */
-               if (bus_if->state != BRCMF_BUS_DATA) {
-                       brcmf_dbg(ERROR, "failed bus is not ready\n");
-                       return -EAGAIN;
-               }
+       /* If bus is not ready, can't continue */
+       if (bus_if->state != BRCMF_BUS_DATA) {
+               brcmf_dbg(ERROR, "failed bus is not ready\n");
+               return -EAGAIN;
+       }
 
-               atomic_set(&drvr->pend_8021x_cnt, 0);
+       atomic_set(&drvr->pend_8021x_cnt, 0);
 
-               memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
+       memcpy(ndev->dev_addr, drvr->mac, ETH_ALEN);
 
-               /* Get current TOE mode from dongle */
-               if (brcmf_toe_get(drvr, ifp->idx, &toe_ol) >= 0
-                   && (toe_ol & TOE_TX_CSUM_OL) != 0)
-                       drvr->iflist[ifp->idx]->ndev->features |=
-                               NETIF_F_IP_CSUM;
-               else
-                       drvr->iflist[ifp->idx]->ndev->features &=
-                               ~NETIF_F_IP_CSUM;
-       }
+       /* Get current TOE mode from dongle */
+       if (brcmf_fil_iovar_int_get(ifp, "toe_ol", &toe_ol) >= 0
+           && (toe_ol & TOE_TX_CSUM_OL) != 0)
+               drvr->iflist[ifp->idx]->ndev->features |=
+                       NETIF_F_IP_CSUM;
+       else
+               drvr->iflist[ifp->idx]->ndev->features &=
+                       ~NETIF_F_IP_CSUM;
 
        /* make sure RF is ready for work */
-       brcmf_proto_cdc_set_dcmd(drvr, 0, BRCMF_C_UP, (char *)&up, sizeof(up));
+       brcmf_fil_cmd_int_set(ifp, BRCMF_C_UP, 0);
 
        /* Allow transmit calls */
        netif_start_queue(ndev);
        drvr->bus_if->drvr_up = true;
-       if (brcmf_cfg80211_up(drvr->config)) {
+       if (brcmf_cfg80211_up(ndev)) {
                brcmf_dbg(ERROR, "failed to bring up cfg80211\n");
                return -1;
        }
@@ -779,39 +600,38 @@ static const struct net_device_ops brcmf_netdev_ops_pri = {
        .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
 };
 
+static const struct net_device_ops brcmf_netdev_ops_virt = {
+       .ndo_open = brcmf_cfg80211_up,
+       .ndo_stop = brcmf_cfg80211_down,
+       .ndo_get_stats = brcmf_netdev_get_stats,
+       .ndo_do_ioctl = brcmf_netdev_ioctl_entry,
+       .ndo_start_xmit = brcmf_netdev_start_xmit,
+       .ndo_set_mac_address = brcmf_netdev_set_mac_address,
+       .ndo_set_rx_mode = brcmf_netdev_set_multicast_list
+};
+
 int brcmf_net_attach(struct brcmf_if *ifp)
 {
        struct brcmf_pub *drvr = ifp->drvr;
        struct net_device *ndev;
-       u8 temp_addr[ETH_ALEN];
-
-       brcmf_dbg(TRACE, "ifidx %d\n", ifp->idx);
 
-       ndev = drvr->iflist[ifp->idx]->ndev;
-       ndev->netdev_ops = &brcmf_netdev_ops_pri;
+       brcmf_dbg(TRACE, "ifidx %d mac %pM\n", ifp->idx, ifp->mac_addr);
+       ndev = ifp->ndev;
 
-       /*
-        * determine mac address to use
-        */
-       if (is_valid_ether_addr(ifp->mac_addr))
-               memcpy(temp_addr, ifp->mac_addr, ETH_ALEN);
+       /* set appropriate operations */
+       if (!ifp->idx)
+               ndev->netdev_ops = &brcmf_netdev_ops_pri;
        else
-               memcpy(temp_addr, drvr->mac, ETH_ALEN);
-
-       if (ifp->idx == 1) {
-               brcmf_dbg(TRACE, "ACCESS POINT MAC:\n");
-               /*  ACCESSPOINT INTERFACE CASE */
-               temp_addr[0] |= 0X02;   /* set bit 2 ,
-                        - Locally Administered address  */
+               ndev->netdev_ops = &brcmf_netdev_ops_virt;
 
-       }
        ndev->hard_header_len = ETH_HLEN + drvr->hdrlen;
        ndev->ethtool_ops = &brcmf_ethtool_ops;
 
        drvr->rxsz = ndev->mtu + ndev->hard_header_len +
                              drvr->hdrlen;
 
-       memcpy(ndev->dev_addr, temp_addr, ETH_ALEN);
+       /* set the mac address */
+       memcpy(ndev->dev_addr, ifp->mac_addr, ETH_ALEN);
 
        if (register_netdev(ndev) != 0) {
                brcmf_dbg(ERROR, "couldn't register the net device\n");
@@ -824,17 +644,15 @@ int brcmf_net_attach(struct brcmf_if *ifp)
 
 fail:
        ndev->netdev_ops = NULL;
-       free_netdev(ndev);
        return -EBADE;
 }
 
-struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
-                             char *name, u8 *mac_addr)
+struct brcmf_if *brcmf_add_if(struct brcmf_pub *drvr, int ifidx, s32 bssidx,
+                             char *name, u8 *addr_mask)
 {
        struct brcmf_if *ifp;
        struct net_device *ndev;
-       struct brcmf_bus *bus_if = dev_get_drvdata(dev);
-       struct brcmf_pub *drvr = bus_if->drvr;
+       int i;
 
        brcmf_dbg(TRACE, "idx %d\n", ifidx);
 
@@ -844,12 +662,17 @@ struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
         * in case we missed the BRCMF_E_IF_DEL event.
         */
        if (ifp) {
-               brcmf_dbg(ERROR, "ERROR: netdev:%s already exists, try free & unregister\n",
+               brcmf_dbg(ERROR, "ERROR: netdev:%s already exists\n",
                          ifp->ndev->name);
-               netif_stop_queue(ifp->ndev);
-               unregister_netdev(ifp->ndev);
-               free_netdev(ifp->ndev);
-               drvr->iflist[ifidx] = NULL;
+               if (ifidx) {
+                       netif_stop_queue(ifp->ndev);
+                       unregister_netdev(ifp->ndev);
+                       free_netdev(ifp->ndev);
+                       drvr->iflist[ifidx] = NULL;
+               } else {
+                       brcmf_dbg(ERROR, "ignore IF event\n");
+                       return ERR_PTR(-EINVAL);
+               }
        }
 
        /* Allocate netdev, including space for private structure */
@@ -865,11 +688,16 @@ struct brcmf_if *brcmf_add_if(struct device *dev, int ifidx, s32 bssidx,
        drvr->iflist[ifidx] = ifp;
        ifp->idx = ifidx;
        ifp->bssidx = bssidx;
-       if (mac_addr != NULL)
-               memcpy(&ifp->mac_addr, mac_addr, ETH_ALEN);
 
-       brcmf_dbg(TRACE, " ==== pid:%x, net_device for if:%s created ===\n",
-                 current->pid, ifp->ndev->name);
+       INIT_WORK(&ifp->setmacaddr_work, _brcmf_set_mac_address);
+       INIT_WORK(&ifp->multicast_work, _brcmf_set_multicast_list);
+
+       if (addr_mask != NULL)
+               for (i = 0; i < ETH_ALEN; i++)
+                       ifp->mac_addr[i] = drvr->mac[i] ^ addr_mask[i];
+
+       brcmf_dbg(TRACE, " ==== pid:%x, if:%s (%pM) created ===\n",
+                 current->pid, ifp->ndev->name, ifp->mac_addr);
 
        return ifp;
 }
@@ -896,6 +724,9 @@ void brcmf_del_if(struct brcmf_pub *drvr, int ifidx)
                        netif_stop_queue(ifp->ndev);
                }
 
+               cancel_work_sync(&ifp->setmacaddr_work);
+               cancel_work_sync(&ifp->multicast_work);
+
                unregister_netdev(ifp->ndev);
                drvr->iflist[ifidx] = NULL;
                if (ifidx == 0)
@@ -934,11 +765,13 @@ int brcmf_attach(uint bus_hdrlen, struct device *dev)
                goto fail;
        }
 
-       INIT_WORK(&drvr->setmacaddr_work, _brcmf_set_mac_address);
-       INIT_WORK(&drvr->multicast_work, _brcmf_set_multicast_list);
+       /* attach firmware event handler */
+       brcmf_fweh_attach(drvr);
 
        INIT_LIST_HEAD(&drvr->bus_if->dcmd_list);
 
+       init_waitqueue_head(&drvr->pend_8021x_wait);
+
        return ret;
 
 fail:
@@ -964,7 +797,7 @@ int brcmf_bus_start(struct device *dev)
        }
 
        /* add primary networking interface */
-       ifp = brcmf_add_if(dev, 0, 0, "wlan%d", NULL);
+       ifp = brcmf_add_if(drvr, 0, 0, "wlan%d", NULL);
        if (IS_ERR(ifp))
                return PTR_ERR(ifp);
 
@@ -974,15 +807,25 @@ int brcmf_bus_start(struct device *dev)
        /* Bus is ready, do any initialization */
        ret = brcmf_c_preinit_dcmds(ifp);
        if (ret < 0)
-               return ret;
+               goto fail;
 
        drvr->config = brcmf_cfg80211_attach(drvr);
-       if (drvr->config == NULL)
-               return -ENOMEM;
+       if (drvr->config == NULL) {
+               ret = -ENOMEM;
+               goto fail;
+       }
+
+       ret = brcmf_fweh_activate_events(ifp);
+       if (ret < 0)
+               goto fail;
 
        ret = brcmf_net_attach(ifp);
+fail:
        if (ret < 0) {
-               brcmf_dbg(ERROR, "brcmf_net_attach failed");
+               brcmf_dbg(ERROR, "failed: %d\n", ret);
+               if (drvr->config)
+                       brcmf_cfg80211_detach(drvr->config);
+               free_netdev(drvr->iflist[0]->ndev);
                drvr->iflist[0] = NULL;
                return ret;
        }
@@ -1011,6 +854,11 @@ void brcmf_detach(struct device *dev)
 
        brcmf_dbg(TRACE, "Enter\n");
 
+       if (drvr == NULL)
+               return;
+
+       /* stop firmware event handling */
+       brcmf_fweh_detach(drvr);
 
        /* make sure primary interface removed last */
        for (i = BRCMF_MAX_IFS-1; i > -1; i--)
@@ -1020,8 +868,6 @@ void brcmf_detach(struct device *dev)
        brcmf_bus_detach(drvr);
 
        if (drvr->prot) {
-               cancel_work_sync(&drvr->setmacaddr_work);
-               cancel_work_sync(&drvr->multicast_work);
                brcmf_proto_detach(drvr);
        }
 
@@ -1035,26 +881,19 @@ static int brcmf_get_pend_8021x_cnt(struct brcmf_pub *drvr)
        return atomic_read(&drvr->pend_8021x_cnt);
 }
 
-#define MAX_WAIT_FOR_8021X_TX  10
-
 int brcmf_netdev_wait_pend8021x(struct net_device *ndev)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_pub *drvr = ifp->drvr;
-       int timeout = 10 * HZ / 1000;
-       int ntimes = MAX_WAIT_FOR_8021X_TX;
-       int pend = brcmf_get_pend_8021x_cnt(drvr);
-
-       while (ntimes && pend) {
-               if (pend) {
-                       set_current_state(TASK_INTERRUPTIBLE);
-                       schedule_timeout(timeout);
-                       set_current_state(TASK_RUNNING);
-                       ntimes--;
-               }
-               pend = brcmf_get_pend_8021x_cnt(drvr);
-       }
-       return pend;
+       int err;
+
+       err = wait_event_timeout(drvr->pend_8021x_wait,
+                                !brcmf_get_pend_8021x_cnt(drvr),
+                                msecs_to_jiffies(MAX_WAIT_FOR_8021X_TX));
+
+       WARN_ON(!err);
+
+       return !err;
 }
 
 static void brcmf_driver_init(struct work_struct *work)
index 7fe6779b90cfbc829488e70e22482a6ca1cad08a..48fa70302192d3f7e6c18f001f00b22dc176b009 100644 (file)
@@ -36,14 +36,7 @@ extern void brcmf_proto_stop(struct brcmf_pub *drvr);
 extern void brcmf_proto_hdrpush(struct brcmf_pub *, int ifidx,
                                struct sk_buff *txp);
 
-/* Use protocol to issue command to dongle */
-extern int brcmf_proto_dcmd(struct brcmf_pub *drvr, int ifidx,
-                               struct brcmf_dcmd *dcmd, int len);
-
 /* Sets dongle media info (drv_version, mac address). */
 extern int brcmf_c_preinit_dcmds(struct brcmf_if *ifp);
 
-extern int brcmf_proto_cdc_set_dcmd(struct brcmf_pub *drvr, int ifidx,
-                                    uint cmd, void *buf, uint len);
-
 #endif                         /* _BRCMF_PROTO_H_ */
index 415f2be3637500fef95ca28d0fe87f556d5b2684..45725454714d5561583939c6212ef03cea5199e6 100644 (file)
@@ -533,9 +533,11 @@ struct brcmf_sdio {
        u8 *rxbuf;              /* Buffer for receiving control packets */
        uint rxblen;            /* Allocated length of rxbuf */
        u8 *rxctl;              /* Aligned pointer into rxbuf */
+       u8 *rxctl_orig;         /* pointer for freeing rxctl */
        u8 *databuf;            /* Buffer for receiving big glom packet */
        u8 *dataptr;            /* Aligned pointer into databuf */
        uint rxlen;             /* Length of valid data in buffer */
+       spinlock_t rxctl_lock;  /* protection lock for ctrl frame resources */
 
        u8 sdpcm_ver;   /* Bus protocol reported by dongle */
 
@@ -582,8 +584,6 @@ struct brcmf_sdio {
        struct list_head dpc_tsklst;
        spinlock_t dpc_tl_lock;
 
-       struct semaphore sdsem;
-
        const struct firmware *firmware;
        u32 fw_ptr;
 
@@ -1037,9 +1037,9 @@ static void brcmf_sdbrcm_free_glom(struct brcmf_sdio *bus)
        }
 }
 
-static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
-                               struct brcmf_sdio_read *rd,
-                               enum brcmf_sdio_frmtype type)
+static int brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
+                              struct brcmf_sdio_read *rd,
+                              enum brcmf_sdio_frmtype type)
 {
        u16 len, checksum;
        u8 rx_seq, fc, tx_seq_max;
@@ -1054,26 +1054,26 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
        /* All zero means no more to read */
        if (!(len | checksum)) {
                bus->rxpending = false;
-               return false;
+               return -ENODATA;
        }
        if ((u16)(~(len ^ checksum))) {
                brcmf_dbg(ERROR, "HW header checksum error\n");
                bus->sdcnt.rx_badhdr++;
                brcmf_sdbrcm_rxfail(bus, false, false);
-               return false;
+               return -EIO;
        }
        if (len < SDPCM_HDRLEN) {
                brcmf_dbg(ERROR, "HW header length error\n");
-               return false;
+               return -EPROTO;
        }
        if (type == BRCMF_SDIO_FT_SUPER &&
            (roundup(len, bus->blocksize) != rd->len)) {
                brcmf_dbg(ERROR, "HW superframe header length error\n");
-               return false;
+               return -EPROTO;
        }
        if (type == BRCMF_SDIO_FT_SUB && len > rd->len) {
                brcmf_dbg(ERROR, "HW subframe header length error\n");
-               return false;
+               return -EPROTO;
        }
        rd->len = len;
 
@@ -1091,7 +1091,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
            SDPCM_GLOMDESC(&header[SDPCM_FRAMETAG_LEN])) {
                brcmf_dbg(ERROR, "Glom descriptor found in superframe head\n");
                rd->len = 0;
-               return false;
+               return -EINVAL;
        }
        rx_seq = SDPCM_PACKET_SEQUENCE(&header[SDPCM_FRAMETAG_LEN]);
        rd->channel = SDPCM_PACKET_CHANNEL(&header[SDPCM_FRAMETAG_LEN]);
@@ -1102,18 +1102,18 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
                bus->sdcnt.rx_toolong++;
                brcmf_sdbrcm_rxfail(bus, false, false);
                rd->len = 0;
-               return false;
+               return -EPROTO;
        }
        if (type == BRCMF_SDIO_FT_SUPER && rd->channel != SDPCM_GLOM_CHANNEL) {
                brcmf_dbg(ERROR, "Wrong channel for superframe\n");
                rd->len = 0;
-               return false;
+               return -EINVAL;
        }
        if (type == BRCMF_SDIO_FT_SUB && rd->channel != SDPCM_DATA_CHANNEL &&
            rd->channel != SDPCM_EVENT_CHANNEL) {
                brcmf_dbg(ERROR, "Wrong channel for subframe\n");
                rd->len = 0;
-               return false;
+               return -EINVAL;
        }
        rd->dat_offset = SDPCM_DOFFSET_VALUE(&header[SDPCM_FRAMETAG_LEN]);
        if (rd->dat_offset < SDPCM_HDRLEN || rd->dat_offset > rd->len) {
@@ -1121,7 +1121,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
                bus->sdcnt.rx_badhdr++;
                brcmf_sdbrcm_rxfail(bus, false, false);
                rd->len = 0;
-               return false;
+               return -ENXIO;
        }
        if (rd->seq_num != rx_seq) {
                brcmf_dbg(ERROR, "seq %d: sequence number error, expect %d\n",
@@ -1131,7 +1131,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
        }
        /* no need to check the reset for subframe */
        if (type == BRCMF_SDIO_FT_SUB)
-               return true;
+               return 0;
        rd->len_nxtfrm = header[SDPCM_FRAMETAG_LEN + SDPCM_NEXTLEN_OFFSET];
        if (rd->len_nxtfrm << 4 > MAX_RX_DATASZ) {
                /* only warm for NON glom packet */
@@ -1155,7 +1155,7 @@ static bool brcmf_sdio_hdparser(struct brcmf_sdio *bus, u8 *header,
        }
        bus->tx_max = tx_seq_max;
 
-       return true;
+       return 0;
 }
 
 static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
@@ -1272,6 +1272,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                 * read directly into the chained packet, or allocate a large
                 * packet and and copy into the chain.
                 */
+               sdio_claim_host(bus->sdiodev->func[1]);
                if (usechain) {
                        errcode = brcmf_sdcard_recv_chain(bus->sdiodev,
                                        bus->sdiodev->sbwad,
@@ -1293,6 +1294,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                  dlen);
                        errcode = -1;
                }
+               sdio_release_host(bus->sdiodev->func[1]);
                bus->sdcnt.f2rxdata++;
 
                /* On failure, kill the superframe, allow a couple retries */
@@ -1301,6 +1303,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                  dlen, errcode);
                        bus->sdiodev->bus_if->dstats.rx_errors++;
 
+                       sdio_claim_host(bus->sdiodev->func[1]);
                        if (bus->glomerr++ < 3) {
                                brcmf_sdbrcm_rxfail(bus, true, true);
                        } else {
@@ -1309,6 +1312,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                bus->sdcnt.rxglomfail++;
                                brcmf_sdbrcm_free_glom(bus);
                        }
+                       sdio_release_host(bus->sdiodev->func[1]);
                        return 0;
                }
 
@@ -1318,8 +1322,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 
                rd_new.seq_num = rxseq;
                rd_new.len = dlen;
-               errcode = -!brcmf_sdio_hdparser(bus, pfirst->data, &rd_new,
-                                                  BRCMF_SDIO_FT_SUPER);
+               sdio_claim_host(bus->sdiodev->func[1]);
+               errcode = brcmf_sdio_hdparser(bus, pfirst->data, &rd_new,
+                                             BRCMF_SDIO_FT_SUPER);
+               sdio_release_host(bus->sdiodev->func[1]);
                bus->cur_read.len = rd_new.len_nxtfrm << 4;
 
                /* Remove superframe header, remember offset */
@@ -1335,9 +1341,10 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
 
                        rd_new.len = pnext->len;
                        rd_new.seq_num = rxseq++;
-                       errcode = -!brcmf_sdio_hdparser(bus, pnext->data,
-                                                          &rd_new,
-                                                          BRCMF_SDIO_FT_SUB);
+                       sdio_claim_host(bus->sdiodev->func[1]);
+                       errcode = brcmf_sdio_hdparser(bus, pnext->data, &rd_new,
+                                                     BRCMF_SDIO_FT_SUB);
+                       sdio_release_host(bus->sdiodev->func[1]);
                        brcmf_dbg_hex_dump(BRCMF_GLOM_ON(),
                                           pnext->data, 32, "subframe:\n");
 
@@ -1347,6 +1354,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                if (errcode) {
                        /* Terminate frame on error, request
                                 a couple retries */
+                       sdio_claim_host(bus->sdiodev->func[1]);
                        if (bus->glomerr++ < 3) {
                                /* Restore superframe header space */
                                skb_push(pfirst, sfdoff);
@@ -1357,6 +1365,7 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                bus->sdcnt.rxglomfail++;
                                brcmf_sdbrcm_free_glom(bus);
                        }
+                       sdio_release_host(bus->sdiodev->func[1]);
                        bus->cur_read.len = 0;
                        return 0;
                }
@@ -1397,11 +1406,8 @@ static u8 brcmf_sdbrcm_rxglom(struct brcmf_sdio *bus, u8 rxseq)
                                           pfirst->prev);
                }
                /* sent any remaining packets up */
-               if (bus->glom.qlen) {
-                       up(&bus->sdsem);
+               if (bus->glom.qlen)
                        brcmf_rx_frame(bus->sdiodev->dev, ifidx, &bus->glom);
-                       down(&bus->sdsem);
-               }
 
                bus->sdcnt.rxglomframes++;
                bus->sdcnt.rxglompkts += bus->glom.qlen;
@@ -1442,21 +1448,24 @@ static void
 brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
 {
        uint rdlen, pad;
-
+       u8 *buf = NULL, *rbuf;
        int sdret;
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       /* Set rxctl for frame (w/optional alignment) */
-       bus->rxctl = bus->rxbuf;
-       bus->rxctl += BRCMF_FIRSTREAD;
-       pad = ((unsigned long)bus->rxctl % BRCMF_SDALIGN);
+       if (bus->rxblen)
+               buf = vzalloc(bus->rxblen);
+       if (!buf) {
+               brcmf_dbg(ERROR, "no memory for control frame\n");
+               goto done;
+       }
+       rbuf = bus->rxbuf;
+       pad = ((unsigned long)rbuf % BRCMF_SDALIGN);
        if (pad)
-               bus->rxctl += (BRCMF_SDALIGN - pad);
-       bus->rxctl -= BRCMF_FIRSTREAD;
+               rbuf += (BRCMF_SDALIGN - pad);
 
        /* Copy the already-read portion over */
-       memcpy(bus->rxctl, hdr, BRCMF_FIRSTREAD);
+       memcpy(buf, hdr, BRCMF_FIRSTREAD);
        if (len <= BRCMF_FIRSTREAD)
                goto gotpkt;
 
@@ -1493,11 +1502,11 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                goto done;
        }
 
-       /* Read remainder of frame body into the rxctl buffer */
+       /* Read remain of frame body */
        sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
                                bus->sdiodev->sbwad,
                                SDIO_FUNC_2,
-                               F2SYNC, (bus->rxctl + BRCMF_FIRSTREAD), rdlen);
+                               F2SYNC, rbuf, rdlen);
        bus->sdcnt.f2rxdata++;
 
        /* Control frame failures need retransmission */
@@ -1507,16 +1516,26 @@ brcmf_sdbrcm_read_control(struct brcmf_sdio *bus, u8 *hdr, uint len, uint doff)
                bus->sdcnt.rxc_errors++;
                brcmf_sdbrcm_rxfail(bus, true, true);
                goto done;
-       }
+       } else
+               memcpy(buf + BRCMF_FIRSTREAD, rbuf, rdlen);
 
 gotpkt:
 
        brcmf_dbg_hex_dump(BRCMF_BYTES_ON() && BRCMF_CTL_ON(),
-                          bus->rxctl, len, "RxCtrl:\n");
+                          buf, len, "RxCtrl:\n");
 
        /* Point to valid data and indicate its length */
-       bus->rxctl += doff;
+       spin_lock_bh(&bus->rxctl_lock);
+       if (bus->rxctl) {
+               brcmf_dbg(ERROR, "last control frame is being processed.\n");
+               spin_unlock_bh(&bus->rxctl_lock);
+               vfree(buf);
+               goto done;
+       }
+       bus->rxctl = buf + doff;
+       bus->rxctl_orig = buf;
        bus->rxlen = len - doff;
+       spin_unlock_bh(&bus->rxctl_lock);
 
 done:
        /* Awake any waiters */
@@ -1571,6 +1590,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
 
                rd->len_left = rd->len;
                /* read header first for unknow frame length */
+               sdio_claim_host(bus->sdiodev->func[1]);
                if (!rd->len) {
                        sdret = brcmf_sdcard_recv_buf(bus->sdiodev,
                                                      bus->sdiodev->sbwad,
@@ -1583,6 +1603,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                          sdret);
                                bus->sdcnt.rx_hdrfail++;
                                brcmf_sdbrcm_rxfail(bus, true, true);
+                               sdio_release_host(bus->sdiodev->func[1]);
                                continue;
                        }
 
@@ -1590,8 +1611,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                           bus->rxhdr, SDPCM_HDRLEN,
                                           "RxHdr:\n");
 
-                       if (!brcmf_sdio_hdparser(bus, bus->rxhdr, rd,
-                                                BRCMF_SDIO_FT_NORMAL)) {
+                       if (brcmf_sdio_hdparser(bus, bus->rxhdr, rd,
+                                               BRCMF_SDIO_FT_NORMAL)) {
+                               sdio_release_host(bus->sdiodev->func[1]);
                                if (!bus->rxpending)
                                        break;
                                else
@@ -1607,6 +1629,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                rd->len_nxtfrm = 0;
                                /* treat all packet as event if we don't know */
                                rd->channel = SDPCM_EVENT_CHANNEL;
+                               sdio_release_host(bus->sdiodev->func[1]);
                                continue;
                        }
                        rd->len_left = rd->len > BRCMF_FIRSTREAD ?
@@ -1624,6 +1647,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                        bus->sdiodev->bus_if->dstats.rx_dropped++;
                        brcmf_sdbrcm_rxfail(bus, false,
                                            RETRYCHAN(rd->channel));
+                       sdio_release_host(bus->sdiodev->func[1]);
                        continue;
                }
                skb_pull(pkt, head_read);
@@ -1632,14 +1656,17 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                sdret = brcmf_sdcard_recv_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                              SDIO_FUNC_2, F2SYNC, pkt);
                bus->sdcnt.f2rxdata++;
+               sdio_release_host(bus->sdiodev->func[1]);
 
                if (sdret < 0) {
                        brcmf_dbg(ERROR, "read %d bytes from channel %d failed: %d\n",
                                  rd->len, rd->channel, sdret);
                        brcmu_pkt_buf_free_skb(pkt);
                        bus->sdiodev->bus_if->dstats.rx_errors++;
+                       sdio_claim_host(bus->sdiodev->func[1]);
                        brcmf_sdbrcm_rxfail(bus, true,
                                            RETRYCHAN(rd->channel));
+                       sdio_release_host(bus->sdiodev->func[1]);
                        continue;
                }
 
@@ -1650,8 +1677,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                } else {
                        memcpy(bus->rxhdr, pkt->data, SDPCM_HDRLEN);
                        rd_new.seq_num = rd->seq_num;
-                       if (!brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new,
-                                                BRCMF_SDIO_FT_NORMAL)) {
+                       sdio_claim_host(bus->sdiodev->func[1]);
+                       if (brcmf_sdio_hdparser(bus, bus->rxhdr, &rd_new,
+                                               BRCMF_SDIO_FT_NORMAL)) {
                                rd->len = 0;
                                brcmu_pkt_buf_free_skb(pkt);
                        }
@@ -1662,9 +1690,11 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                          roundup(rd_new.len, 16) >> 4);
                                rd->len = 0;
                                brcmf_sdbrcm_rxfail(bus, true, true);
+                               sdio_release_host(bus->sdiodev->func[1]);
                                brcmu_pkt_buf_free_skb(pkt);
                                continue;
                        }
+                       sdio_release_host(bus->sdiodev->func[1]);
                        rd->len_nxtfrm = rd_new.len_nxtfrm;
                        rd->channel = rd_new.channel;
                        rd->dat_offset = rd_new.dat_offset;
@@ -1680,7 +1710,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                                          rd_new.seq_num);
                                /* Force retry w/normal header read */
                                rd->len = 0;
+                               sdio_claim_host(bus->sdiodev->func[1]);
                                brcmf_sdbrcm_rxfail(bus, false, true);
+                               sdio_release_host(bus->sdiodev->func[1]);
                                brcmu_pkt_buf_free_skb(pkt);
                                continue;
                        }
@@ -1703,7 +1735,9 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                        } else {
                                brcmf_dbg(ERROR, "%s: glom superframe w/o "
                                          "descriptor!\n", __func__);
+                               sdio_claim_host(bus->sdiodev->func[1]);
                                brcmf_sdbrcm_rxfail(bus, false, false);
+                               sdio_release_host(bus->sdiodev->func[1]);
                        }
                        /* prepare the descriptor for the next read */
                        rd->len = rd->len_nxtfrm << 4;
@@ -1734,10 +1768,7 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
                        continue;
                }
 
-               /* Unlock during rx call */
-               up(&bus->sdsem);
                brcmf_rx_packet(bus->sdiodev->dev, ifidx, pkt);
-               down(&bus->sdsem);
        }
 
        rxcount = maxframes - rxleft;
@@ -1754,15 +1785,6 @@ static uint brcmf_sdio_readframes(struct brcmf_sdio *bus, uint maxframes)
        return rxcount;
 }
 
-static void
-brcmf_sdbrcm_wait_for_event(struct brcmf_sdio *bus, bool *lockvar)
-{
-       up(&bus->sdsem);
-       wait_event_interruptible_timeout(bus->ctrl_wait, !*lockvar, HZ * 2);
-       down(&bus->sdsem);
-       return;
-}
-
 static void
 brcmf_sdbrcm_wait_event_wakeup(struct brcmf_sdio *bus)
 {
@@ -1864,6 +1886,7 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
        if (len & (ALIGNMENT - 1))
                        len = roundup(len, ALIGNMENT);
 
+       sdio_claim_host(bus->sdiodev->func[1]);
        ret = brcmf_sdcard_send_pkt(bus->sdiodev, bus->sdiodev->sbwad,
                                    SDIO_FUNC_2, F2SYNC, pkt);
        bus->sdcnt.f2txdata++;
@@ -1891,15 +1914,14 @@ static int brcmf_sdbrcm_txpkt(struct brcmf_sdio *bus, struct sk_buff *pkt,
                }
 
        }
+       sdio_release_host(bus->sdiodev->func[1]);
        if (ret == 0)
                bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
 
 done:
        /* restore pkt buffer pointer before calling tx complete routine */
        skb_pull(pkt, SDPCM_HDRLEN + pad);
-       up(&bus->sdsem);
        brcmf_txcomplete(bus->sdiodev->dev, pkt, ret != 0);
-       down(&bus->sdsem);
 
        if (free_pkt)
                brcmu_pkt_buf_free_skb(pkt);
@@ -1940,9 +1962,11 @@ static uint brcmf_sdbrcm_sendfromq(struct brcmf_sdio *bus, uint maxframes)
                /* In poll mode, need to check for other events */
                if (!bus->intr && cnt) {
                        /* Check device status, signal pending interrupt */
+                       sdio_claim_host(bus->sdiodev->func[1]);
                        ret = r_sdreg32(bus, &intstatus,
                                        offsetof(struct sdpcmd_regs,
                                                 intstatus));
+                       sdio_release_host(bus->sdiodev->func[1]);
                        bus->sdcnt.f2txdata++;
                        if (ret != 0)
                                break;
@@ -1979,7 +2003,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
                bus->watchdog_tsk = NULL;
        }
 
-       down(&bus->sdsem);
+       sdio_claim_host(bus->sdiodev->func[1]);
 
        /* Enable clock for device interrupts */
        brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
@@ -2013,6 +2037,7 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
 
        /* Turn off the backplane clock (only) */
        brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
+       sdio_release_host(bus->sdiodev->func[1]);
 
        /* Clear the data packet queues */
        brcmu_pktq_flush(&bus->txq, true, NULL, NULL);
@@ -2023,14 +2048,14 @@ static void brcmf_sdbrcm_bus_stop(struct device *dev)
        brcmf_sdbrcm_free_glom(bus);
 
        /* Clear rx control and wake any waiters */
+       spin_lock_bh(&bus->rxctl_lock);
        bus->rxlen = 0;
+       spin_unlock_bh(&bus->rxctl_lock);
        brcmf_sdbrcm_dcmd_resp_wake(bus);
 
        /* Reset some F2 state stuff */
        bus->rxskip = false;
        bus->tx_seq = bus->rx_seq = 0;
-
-       up(&bus->sdsem);
 }
 
 #ifdef CONFIG_BRCMFMAC_SDIO_OOB
@@ -2114,7 +2139,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
 
        brcmf_dbg(TRACE, "Enter\n");
 
-       down(&bus->sdsem);
+       sdio_claim_host(bus->sdiodev->func[1]);
 
        /* If waiting for HTAVAIL, check status */
        if (bus->clkstate == CLK_PENDING) {
@@ -2168,9 +2193,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
        /* Pending interrupt indicates new device status */
        if (atomic_read(&bus->ipend) > 0) {
                atomic_set(&bus->ipend, 0);
-               sdio_claim_host(bus->sdiodev->func[1]);
                err = brcmf_sdio_intr_rstatus(bus);
-               sdio_release_host(bus->sdiodev->func[1]);
        }
 
        /* Start with leftover status bits */
@@ -2199,6 +2222,8 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                intstatus |= brcmf_sdbrcm_hostmail(bus);
        }
 
+       sdio_release_host(bus->sdiodev->func[1]);
+
        /* Generally don't ask for these, can get CRC errors... */
        if (intstatus & I_WR_OOSYNC) {
                brcmf_dbg(ERROR, "Dongle reports WR_OOSYNC\n");
@@ -2245,6 +2270,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                (bus->clkstate == CLK_AVAIL)) {
                int i;
 
+               sdio_claim_host(bus->sdiodev->func[1]);
                err = brcmf_sdcard_send_buf(bus->sdiodev, bus->sdiodev->sbwad,
                        SDIO_FUNC_2, F2SYNC, bus->ctrl_frame_buf,
                        (u32) bus->ctrl_frame_len);
@@ -2278,6 +2304,7 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
                } else {
                        bus->tx_seq = (bus->tx_seq + 1) % SDPCM_SEQUENCE_WRAP;
                }
+               sdio_release_host(bus->sdiodev->func[1]);
                bus->ctrl_frame_stat = false;
                brcmf_sdbrcm_wait_event_wakeup(bus);
        }
@@ -2307,10 +2334,10 @@ static void brcmf_sdbrcm_dpc(struct brcmf_sdio *bus)
        if ((bus->clkstate != CLK_PENDING)
            && bus->idletime == BRCMF_IDLE_IMMEDIATE) {
                bus->activity = false;
+               sdio_claim_host(bus->sdiodev->func[1]);
                brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+               sdio_release_host(bus->sdiodev->func[1]);
        }
-
-       up(&bus->sdsem);
 }
 
 static int brcmf_sdbrcm_bus_txdata(struct device *dev, struct sk_buff *pkt)
@@ -2601,11 +2628,10 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
 
        /* precondition: IS_ALIGNED((unsigned long)frame, 2) */
 
-       /* Need to lock here to protect txseq and SDIO tx calls */
-       down(&bus->sdsem);
-
        /* Make sure backplane clock is on */
+       sdio_claim_host(bus->sdiodev->func[1]);
        brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
+       sdio_release_host(bus->sdiodev->func[1]);
 
        /* Hardware tag: 2 byte len followed by 2 byte ~len check (all LE) */
        *(__le16 *) frame = cpu_to_le16((u16) msglen);
@@ -2628,7 +2654,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
                bus->ctrl_frame_buf = frame;
                bus->ctrl_frame_len = len;
 
-               brcmf_sdbrcm_wait_for_event(bus, &bus->ctrl_frame_stat);
+               wait_event_interruptible_timeout(bus->ctrl_wait,
+                                                !bus->ctrl_frame_stat,
+                                                msecs_to_jiffies(2000));
 
                if (!bus->ctrl_frame_stat) {
                        brcmf_dbg(INFO, "ctrl_frame_stat == false\n");
@@ -2647,7 +2675,9 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
                                   frame, min_t(u16, len, 16), "TxHdr:\n");
 
                do {
+                       sdio_claim_host(bus->sdiodev->func[1]);
                        ret = brcmf_tx_frame(bus, frame, len);
+                       sdio_release_host(bus->sdiodev->func[1]);
                } while (ret < 0 && retries++ < TXRETRIES);
        }
 
@@ -2657,13 +2687,13 @@ brcmf_sdbrcm_bus_txctl(struct device *dev, unsigned char *msg, uint msglen)
                spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
 
                bus->activity = false;
+               sdio_claim_host(bus->sdiodev->func[1]);
                brcmf_sdbrcm_clkctl(bus, CLK_NONE, true);
+               sdio_release_host(bus->sdiodev->func[1]);
        } else {
                spin_unlock_irqrestore(&bus->dpc_tl_lock, flags);
        }
 
-       up(&bus->sdsem);
-
        if (ret)
                bus->sdcnt.tx_ctlerrs++;
        else
@@ -2693,8 +2723,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
         * Read last word in socram to determine
         * address of sdpcm_shared structure
         */
+       sdio_claim_host(bus->sdiodev->func[1]);
        rv = brcmf_sdbrcm_membytes(bus, false, shaddr,
                                   (u8 *)&addr_le, 4);
+       sdio_claim_host(bus->sdiodev->func[1]);
        if (rv < 0)
                return rv;
 
@@ -2713,8 +2745,10 @@ static int brcmf_sdio_readshared(struct brcmf_sdio *bus,
        }
 
        /* Read hndrte_shared structure */
+       sdio_claim_host(bus->sdiodev->func[1]);
        rv = brcmf_sdbrcm_membytes(bus, false, addr, (u8 *)&sh_le,
                                   sizeof(struct sdpcm_shared_le));
+       sdio_release_host(bus->sdiodev->func[1]);
        if (rv < 0)
                return rv;
 
@@ -2817,12 +2851,14 @@ static int brcmf_sdio_trap_info(struct brcmf_sdio *bus, struct sdpcm_shared *sh,
        if ((sh->flags & SDPCM_SHARED_TRAP) == 0)
                return 0;
 
+       sdio_claim_host(bus->sdiodev->func[1]);
        error = brcmf_sdbrcm_membytes(bus, false, sh->trap_addr, (u8 *)&tr,
                                      sizeof(struct brcmf_trap_info));
        if (error < 0)
                return error;
 
        nbytes = brcmf_sdio_dump_console(bus, sh, data, count);
+       sdio_release_host(bus->sdiodev->func[1]);
        if (nbytes < 0)
                return nbytes;
 
@@ -2868,6 +2904,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
                return 0;
        }
 
+       sdio_claim_host(bus->sdiodev->func[1]);
        if (sh->assert_file_addr != 0) {
                error = brcmf_sdbrcm_membytes(bus, false, sh->assert_file_addr,
                                              (u8 *)file, 80);
@@ -2880,6 +2917,7 @@ static int brcmf_sdio_assert_info(struct brcmf_sdio *bus,
                if (error < 0)
                        return error;
        }
+       sdio_release_host(bus->sdiodev->func[1]);
 
        res = scnprintf(buf, sizeof(buf),
                        "dongle assert: %s:%d: assert(%s)\n",
@@ -2892,9 +2930,7 @@ static int brcmf_sdbrcm_checkdied(struct brcmf_sdio *bus)
        int error;
        struct sdpcm_shared sh;
 
-       down(&bus->sdsem);
        error = brcmf_sdio_readshared(bus, &sh);
-       up(&bus->sdsem);
 
        if (error < 0)
                return error;
@@ -2921,7 +2957,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
        if (pos != 0)
                return 0;
 
-       down(&bus->sdsem);
        error = brcmf_sdio_readshared(bus, &sh);
        if (error < 0)
                goto done;
@@ -2938,7 +2973,6 @@ static int brcmf_sdbrcm_died_dump(struct brcmf_sdio *bus, char __user *data,
        error += nbytes;
        *ppos += error;
 done:
-       up(&bus->sdsem);
        return error;
 }
 
@@ -2989,6 +3023,7 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
        int timeleft;
        uint rxlen = 0;
        bool pending;
+       u8 *buf;
        struct brcmf_bus *bus_if = dev_get_drvdata(dev);
        struct brcmf_sdio_dev *sdiodev = bus_if->bus_priv.sdio;
        struct brcmf_sdio *bus = sdiodev->bus;
@@ -2998,11 +3033,15 @@ brcmf_sdbrcm_bus_rxctl(struct device *dev, unsigned char *msg, uint msglen)
        /* Wait until control frame is available */
        timeleft = brcmf_sdbrcm_dcmd_resp_wait(bus, &bus->rxlen, &pending);
 
-       down(&bus->sdsem);
+       spin_lock_bh(&bus->rxctl_lock);
        rxlen = bus->rxlen;
        memcpy(msg, bus->rxctl, min(msglen, rxlen));
+       bus->rxctl = NULL;
+       buf = bus->rxctl_orig;
+       bus->rxctl_orig = NULL;
        bus->rxlen = 0;
-       up(&bus->sdsem);
+       spin_unlock_bh(&bus->rxctl_lock);
+       vfree(buf);
 
        if (rxlen) {
                brcmf_dbg(CTL, "resumed on rxctl frame, got %d expected %d\n",
@@ -3338,13 +3377,16 @@ brcmf_sdbrcm_download_firmware(struct brcmf_sdio *bus)
 {
        bool ret;
 
-       /* Download the firmware */
+       sdio_claim_host(bus->sdiodev->func[1]);
+
        brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
 
        ret = _brcmf_sdbrcm_download_firmware(bus) == 0;
 
        brcmf_sdbrcm_clkctl(bus, CLK_SDONLY, false);
 
+       sdio_release_host(bus->sdiodev->func[1]);
+
        return ret;
 }
 
@@ -3373,7 +3415,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
        bus->sdcnt.tickcnt = 0;
        brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
 
-       down(&bus->sdsem);
+       sdio_claim_host(bus->sdiodev->func[1]);
 
        /* Make sure backplane clock is on, needed to generate F2 interrupt */
        brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
@@ -3442,7 +3484,7 @@ static int brcmf_sdbrcm_bus_init(struct device *dev)
                brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
 
 exit:
-       up(&bus->sdsem);
+       sdio_release_host(bus->sdiodev->func[1]);
 
        return ret;
 }
@@ -3489,8 +3531,6 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
 
        brcmf_dbg(TIMER, "Enter\n");
 
-       down(&bus->sdsem);
-
        /* Poll period: check device if appropriate. */
        if (bus->poll && (++bus->polltick >= bus->pollrate)) {
                u32 intstatus = 0;
@@ -3507,9 +3547,11 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                                u8 devpend;
                                spin_unlock_irqrestore(&bus->dpc_tl_lock,
                                                       flags);
+                               sdio_claim_host(bus->sdiodev->func[1]);
                                devpend = brcmf_sdio_regrb(bus->sdiodev,
                                                           SDIO_CCCR_INTx,
                                                           NULL);
+                               sdio_release_host(bus->sdiodev->func[1]);
                                intstatus =
                                    devpend & (INTR_STATUS_FUNC1 |
                                               INTR_STATUS_FUNC2);
@@ -3534,16 +3576,18 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
        }
 #ifdef DEBUG
        /* Poll for console output periodically */
-       if (bus_if->state == BRCMF_BUS_DATA &&
+       if (bus_if && bus_if->state == BRCMF_BUS_DATA &&
            bus->console_interval != 0) {
                bus->console.count += BRCMF_WD_POLL_MS;
                if (bus->console.count >= bus->console_interval) {
                        bus->console.count -= bus->console_interval;
+                       sdio_claim_host(bus->sdiodev->func[1]);
                        /* Make sure backplane clock is on */
                        brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
                        if (brcmf_sdbrcm_readconsole(bus) < 0)
                                /* stop on error */
                                bus->console_interval = 0;
+                       sdio_release_host(bus->sdiodev->func[1]);
                }
        }
 #endif                         /* DEBUG */
@@ -3556,13 +3600,13 @@ static bool brcmf_sdbrcm_bus_watchdog(struct brcmf_sdio *bus)
                                bus->activity = false;
                                brcmf_sdbrcm_wd_timer(bus, BRCMF_WD_POLL_MS);
                        } else {
+                               sdio_claim_host(bus->sdiodev->func[1]);
                                brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+                               sdio_release_host(bus->sdiodev->func[1]);
                        }
                }
        }
 
-       up(&bus->sdsem);
-
        return (atomic_read(&bus->ipend) > 0);
 }
 
@@ -3657,6 +3701,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
 
        bus->alp_only = true;
 
+       sdio_claim_host(bus->sdiodev->func[1]);
+
        pr_debug("F1 signature read @0x18000000=0x%4x\n",
                 brcmf_sdio_regrl(bus->sdiodev, SI_ENUM_BASE, NULL));
 
@@ -3704,6 +3750,8 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
        reg_val = brcmf_sdio_regrl(bus->sdiodev, reg_addr, NULL);
        brcmf_sdio_regwl(bus->sdiodev, reg_addr, reg_val | CC_BPRESEN, NULL);
 
+       sdio_release_host(bus->sdiodev->func[1]);
+
        brcmu_pktq_init(&bus->txq, (PRIOMASK + 1), TXQLEN);
 
        /* Locate an appropriately-aligned portion of hdrbuf */
@@ -3719,6 +3767,7 @@ brcmf_sdbrcm_probe_attach(struct brcmf_sdio *bus, u32 regsva)
        return true;
 
 fail:
+       sdio_release_host(bus->sdiodev->func[1]);
        return false;
 }
 
@@ -3726,6 +3775,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
 {
        brcmf_dbg(TRACE, "Enter\n");
 
+       sdio_claim_host(bus->sdiodev->func[1]);
+
        /* Disable F2 to clear any intermediate frame state on the dongle */
        brcmf_sdio_regwb(bus->sdiodev, SDIO_CCCR_IOEx,
                         SDIO_FUNC_ENABLE_1, NULL);
@@ -3736,6 +3787,8 @@ static bool brcmf_sdbrcm_probe_init(struct brcmf_sdio *bus)
        /* Done with backplane-dependent accesses, can drop clock... */
        brcmf_sdio_regwb(bus->sdiodev, SBSDIO_FUNC1_CHIPCLKCSR, 0, NULL);
 
+       sdio_release_host(bus->sdiodev->func[1]);
+
        /* ...and initialize clock/power states */
        bus->clkstate = CLK_SDONLY;
        bus->idletime = BRCMF_IDLE_INTERVAL;
@@ -3791,8 +3844,10 @@ static void brcmf_sdbrcm_release_dongle(struct brcmf_sdio *bus)
        brcmf_dbg(TRACE, "Enter\n");
 
        if (bus->ci) {
+               sdio_claim_host(bus->sdiodev->func[1]);
                brcmf_sdbrcm_clkctl(bus, CLK_AVAIL, false);
                brcmf_sdbrcm_clkctl(bus, CLK_NONE, false);
+               sdio_release_host(bus->sdiodev->func[1]);
                brcmf_sdio_chip_detach(&bus->ci);
                if (bus->vars && bus->varsz)
                        kfree(bus->vars);
@@ -3812,7 +3867,8 @@ static void brcmf_sdbrcm_release(struct brcmf_sdio *bus)
                brcmf_sdio_intr_unregister(bus->sdiodev);
 
                cancel_work_sync(&bus->datawork);
-               destroy_workqueue(bus->brcmf_wq);
+               if (bus->brcmf_wq)
+                       destroy_workqueue(bus->brcmf_wq);
 
                if (bus->sdiodev->bus_if->drvr) {
                        brcmf_detach(bus->sdiodev->dev);
@@ -3854,31 +3910,29 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        bus->txminmax = BRCMF_TXMINMAX;
        bus->tx_seq = SDPCM_SEQUENCE_WRAP - 1;
 
+       INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
+       bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
+       if (bus->brcmf_wq == NULL) {
+               brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n");
+               goto fail;
+       }
+
        /* attempt to attach to the dongle */
        if (!(brcmf_sdbrcm_probe_attach(bus, regsva))) {
                brcmf_dbg(ERROR, "brcmf_sdbrcm_probe_attach failed\n");
                goto fail;
        }
 
+       spin_lock_init(&bus->rxctl_lock);
        spin_lock_init(&bus->txqlock);
        init_waitqueue_head(&bus->ctrl_wait);
        init_waitqueue_head(&bus->dcmd_resp_wait);
 
-       bus->brcmf_wq = create_singlethread_workqueue("brcmf_wq");
-       if (bus->brcmf_wq == NULL) {
-               brcmf_dbg(ERROR, "insufficient memory to create txworkqueue\n");
-               goto fail;
-       }
-       INIT_WORK(&bus->datawork, brcmf_sdio_dataworker);
-
        /* Set up the watchdog timer */
        init_timer(&bus->timer);
        bus->timer.data = (unsigned long)bus;
        bus->timer.function = brcmf_sdbrcm_watchdog;
 
-       /* Initialize thread based operation and lock */
-       sema_init(&bus->sdsem, 1);
-
        /* Initialize watchdog thread */
        init_completion(&bus->watchdog_wait);
        bus->watchdog_tsk = kthread_run(brcmf_sdbrcm_watchdog_thread,
@@ -3941,10 +3995,8 @@ void *brcmf_sdbrcm_probe(u32 regsva, struct brcmf_sdio_dev *sdiodev)
        /* if firmware path present try to download and bring up bus */
        ret = brcmf_bus_start(bus->sdiodev->dev);
        if (ret != 0) {
-               if (ret == -ENOLINK) {
-                       brcmf_dbg(ERROR, "dongle is not responding\n");
-                       goto fail;
-               }
+               brcmf_dbg(ERROR, "dongle is not responding\n");
+               goto fail;
        }
 
        return bus;
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.c b/drivers/net/wireless/brcm80211/brcmfmac/fweh.c
new file mode 100644 (file)
index 0000000..fa8fc44
--- /dev/null
@@ -0,0 +1,509 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+#include <linux/netdevice.h>
+
+#include "brcmu_wifi.h"
+#include "brcmu_utils.h"
+
+#include "dhd.h"
+#include "dhd_dbg.h"
+#include "fweh.h"
+#include "fwil.h"
+
+/**
+ * struct brcm_ethhdr - broadcom specific ether header.
+ *
+ * @subtype: subtype for this packet.
+ * @length: TODO: length of appended data.
+ * @version: version indication.
+ * @oui: OUI of this packet.
+ * @usr_subtype: subtype for this OUI.
+ */
+struct brcm_ethhdr {
+       __be16 subtype;
+       __be16 length;
+       u8 version;
+       u8 oui[3];
+       __be16 usr_subtype;
+} __packed;
+
+struct brcmf_event_msg_be {
+       __be16 version;
+       __be16 flags;
+       __be32 event_type;
+       __be32 status;
+       __be32 reason;
+       __be32 auth_type;
+       __be32 datalen;
+       u8 addr[ETH_ALEN];
+       char ifname[IFNAMSIZ];
+       u8 ifidx;
+       u8 bsscfgidx;
+} __packed;
+
+/**
+ * struct brcmf_event - contents of broadcom event packet.
+ *
+ * @eth: standard ether header.
+ * @hdr: broadcom specific ether header.
+ * @msg: common part of the actual event message.
+ */
+struct brcmf_event {
+       struct ethhdr eth;
+       struct brcm_ethhdr hdr;
+       struct brcmf_event_msg_be msg;
+} __packed;
+
+/**
+ * struct brcmf_fweh_queue_item - event item on event queue.
+ *
+ * @q: list element for queuing.
+ * @code: event code.
+ * @ifidx: interface index related to this event.
+ * @ifaddr: ethernet address for interface.
+ * @emsg: common parameters of the firmware event message.
+ * @data: event specific data part of the firmware event.
+ */
+struct brcmf_fweh_queue_item {
+       struct list_head q;
+       enum brcmf_fweh_event_code code;
+       u8 ifidx;
+       u8 ifaddr[ETH_ALEN];
+       struct brcmf_event_msg_be emsg;
+       u8 data[0];
+};
+
+/**
+ * struct brcmf_fweh_event_name - code, name mapping entry.
+ */
+struct brcmf_fweh_event_name {
+       enum brcmf_fweh_event_code code;
+       const char *name;
+};
+
+#ifdef DEBUG
+/* array for mapping code to event name */
+static struct brcmf_fweh_event_name fweh_event_names[] = {
+       { BRCMF_E_SET_SSID, "SET_SSID" },
+       { BRCMF_E_JOIN, "JOIN" },
+       { BRCMF_E_START, "START" },
+       { BRCMF_E_AUTH, "AUTH" },
+       { BRCMF_E_AUTH_IND, "AUTH_IND" },
+       { BRCMF_E_DEAUTH, "DEAUTH" },
+       { BRCMF_E_DEAUTH_IND, "DEAUTH_IND" },
+       { BRCMF_E_ASSOC, "ASSOC" },
+       { BRCMF_E_ASSOC_IND, "ASSOC_IND" },
+       { BRCMF_E_REASSOC, "REASSOC" },
+       { BRCMF_E_REASSOC_IND, "REASSOC_IND" },
+       { BRCMF_E_DISASSOC, "DISASSOC" },
+       { BRCMF_E_DISASSOC_IND, "DISASSOC_IND" },
+       { BRCMF_E_QUIET_START, "START_QUIET" },
+       { BRCMF_E_QUIET_END, "END_QUIET" },
+       { BRCMF_E_BEACON_RX, "BEACON_RX" },
+       { BRCMF_E_LINK, "LINK" },
+       { BRCMF_E_MIC_ERROR, "MIC_ERROR" },
+       { BRCMF_E_NDIS_LINK, "NDIS_LINK" },
+       { BRCMF_E_ROAM, "ROAM" },
+       { BRCMF_E_TXFAIL, "TXFAIL" },
+       { BRCMF_E_PMKID_CACHE, "PMKID_CACHE" },
+       { BRCMF_E_RETROGRADE_TSF, "RETROGRADE_TSF" },
+       { BRCMF_E_PRUNE, "PRUNE" },
+       { BRCMF_E_AUTOAUTH, "AUTOAUTH" },
+       { BRCMF_E_EAPOL_MSG, "EAPOL_MSG" },
+       { BRCMF_E_SCAN_COMPLETE, "SCAN_COMPLETE" },
+       { BRCMF_E_ADDTS_IND, "ADDTS_IND" },
+       { BRCMF_E_DELTS_IND, "DELTS_IND" },
+       { BRCMF_E_BCNSENT_IND, "BCNSENT_IND" },
+       { BRCMF_E_BCNRX_MSG, "BCNRX_MSG" },
+       { BRCMF_E_BCNLOST_MSG, "BCNLOST_MSG" },
+       { BRCMF_E_ROAM_PREP, "ROAM_PREP" },
+       { BRCMF_E_PFN_NET_FOUND, "PNO_NET_FOUND" },
+       { BRCMF_E_PFN_NET_LOST, "PNO_NET_LOST" },
+       { BRCMF_E_RESET_COMPLETE, "RESET_COMPLETE" },
+       { BRCMF_E_JOIN_START, "JOIN_START" },
+       { BRCMF_E_ROAM_START, "ROAM_START" },
+       { BRCMF_E_ASSOC_START, "ASSOC_START" },
+       { BRCMF_E_IBSS_ASSOC, "IBSS_ASSOC" },
+       { BRCMF_E_RADIO, "RADIO" },
+       { BRCMF_E_PSM_WATCHDOG, "PSM_WATCHDOG" },
+       { BRCMF_E_PROBREQ_MSG, "PROBREQ_MSG" },
+       { BRCMF_E_SCAN_CONFIRM_IND, "SCAN_CONFIRM_IND" },
+       { BRCMF_E_PSK_SUP, "PSK_SUP" },
+       { BRCMF_E_COUNTRY_CODE_CHANGED, "COUNTRY_CODE_CHANGED" },
+       { BRCMF_E_EXCEEDED_MEDIUM_TIME, "EXCEEDED_MEDIUM_TIME" },
+       { BRCMF_E_ICV_ERROR, "ICV_ERROR" },
+       { BRCMF_E_UNICAST_DECODE_ERROR, "UNICAST_DECODE_ERROR" },
+       { BRCMF_E_MULTICAST_DECODE_ERROR, "MULTICAST_DECODE_ERROR" },
+       { BRCMF_E_TRACE, "TRACE" },
+       { BRCMF_E_IF, "IF" },
+       { BRCMF_E_RSSI, "RSSI" },
+       { BRCMF_E_PFN_SCAN_COMPLETE, "PFN_SCAN_COMPLETE" },
+       { BRCMF_E_EXTLOG_MSG, "EXTLOG_MSG" },
+       { BRCMF_E_ACTION_FRAME, "ACTION_FRAME" },
+       { BRCMF_E_ACTION_FRAME_COMPLETE, "ACTION_FRAME_COMPLETE" },
+       { BRCMF_E_PRE_ASSOC_IND, "PRE_ASSOC_IND" },
+       { BRCMF_E_PRE_REASSOC_IND, "PRE_REASSOC_IND" },
+       { BRCMF_E_CHANNEL_ADOPTED, "CHANNEL_ADOPTED" },
+       { BRCMF_E_AP_STARTED, "AP_STARTED" },
+       { BRCMF_E_DFS_AP_STOP, "DFS_AP_STOP" },
+       { BRCMF_E_DFS_AP_RESUME, "DFS_AP_RESUME" },
+       { BRCMF_E_ESCAN_RESULT, "ESCAN_RESULT" },
+       { BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE, "ACTION_FRM_OFF_CHAN_CMPLT" },
+       { BRCMF_E_DCS_REQUEST, "DCS_REQUEST" },
+       { BRCMF_E_FIFO_CREDIT_MAP, "FIFO_CREDIT_MAP"}
+};
+
+/**
+ * brcmf_fweh_event_name() - returns name for given event code.
+ *
+ * @code: code to lookup.
+ */
+static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
+{
+       int i;
+       for (i = 0; i < ARRAY_SIZE(fweh_event_names); i++) {
+               if (fweh_event_names[i].code == code)
+                       return fweh_event_names[i].name;
+       }
+       return "unknown";
+}
+#else
+static const char *brcmf_fweh_event_name(enum brcmf_fweh_event_code code)
+{
+       return "nodebug";
+}
+#endif
+
+/**
+ * brcmf_fweh_queue_event() - create and queue event.
+ *
+ * @fweh: firmware event handling info.
+ * @event: event queue entry.
+ */
+static void brcmf_fweh_queue_event(struct brcmf_fweh_info *fweh,
+                                  struct brcmf_fweh_queue_item *event)
+{
+       ulong flags;
+
+       spin_lock_irqsave(&fweh->evt_q_lock, flags);
+       list_add_tail(&event->q, &fweh->event_q);
+       spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
+       schedule_work(&fweh->event_work);
+}
+
+static int brcmf_fweh_call_event_handler(struct brcmf_if *ifp,
+                                        enum brcmf_fweh_event_code code,
+                                        struct brcmf_event_msg *emsg,
+                                        void *data)
+{
+       struct brcmf_fweh_info *fweh;
+       int err = -EINVAL;
+
+       if (ifp) {
+               fweh = &ifp->drvr->fweh;
+
+               /* handle the event if valid interface and handler */
+               if (ifp->ndev && fweh->evt_handler[code])
+                       err = fweh->evt_handler[code](ifp, emsg, data);
+               else
+                       brcmf_dbg(ERROR, "unhandled event %d ignored\n", code);
+       } else {
+               brcmf_dbg(ERROR, "no interface object\n");
+       }
+       return err;
+}
+
+/**
+ * brcmf_fweh_handle_if_event() - handle IF event.
+ *
+ * @drvr: driver information object.
+ * @item: queue entry.
+ * @ifpp: interface object (may change upon ADD action).
+ */
+static void brcmf_fweh_handle_if_event(struct brcmf_pub *drvr,
+                                      struct brcmf_event_msg *emsg,
+                                      void *data)
+{
+       struct brcmf_if_event *ifevent = data;
+       struct brcmf_if *ifp;
+       int err = 0;
+
+       brcmf_dbg(EVENT, "action: %u idx: %u bsscfg: %u flags: %u\n",
+                 ifevent->action, ifevent->ifidx,
+                 ifevent->bssidx, ifevent->flags);
+
+       if (ifevent->ifidx >= BRCMF_MAX_IFS) {
+               brcmf_dbg(ERROR, "invalid interface index: %u\n",
+                         ifevent->ifidx);
+               return;
+       }
+
+       ifp = drvr->iflist[ifevent->ifidx];
+
+       if (ifevent->action == BRCMF_E_IF_ADD) {
+               brcmf_dbg(EVENT, "adding %s (%pM)\n", emsg->ifname,
+                         emsg->addr);
+               ifp = brcmf_add_if(drvr, ifevent->ifidx, ifevent->bssidx,
+                                  emsg->ifname, emsg->addr);
+               if (IS_ERR(ifp))
+                       return;
+
+               if (!drvr->fweh.evt_handler[BRCMF_E_IF])
+                       err = brcmf_net_attach(ifp);
+       }
+
+       err = brcmf_fweh_call_event_handler(ifp, emsg->event_code, emsg, data);
+
+       if (ifevent->action == BRCMF_E_IF_DEL)
+               brcmf_del_if(drvr, ifevent->ifidx);
+}
+
+/**
+ * brcmf_fweh_dequeue_event() - get event from the queue.
+ *
+ * @fweh: firmware event handling info.
+ */
+static struct brcmf_fweh_queue_item *
+brcmf_fweh_dequeue_event(struct brcmf_fweh_info *fweh)
+{
+       struct brcmf_fweh_queue_item *event = NULL;
+       ulong flags;
+
+       spin_lock_irqsave(&fweh->evt_q_lock, flags);
+       if (!list_empty(&fweh->event_q)) {
+               event = list_first_entry(&fweh->event_q,
+                                        struct brcmf_fweh_queue_item, q);
+               list_del(&event->q);
+       }
+       spin_unlock_irqrestore(&fweh->evt_q_lock, flags);
+
+       return event;
+}
+
+/**
+ * brcmf_fweh_event_worker() - firmware event worker.
+ *
+ * @work: worker object.
+ */
+static void brcmf_fweh_event_worker(struct work_struct *work)
+{
+       struct brcmf_pub *drvr;
+       struct brcmf_if *ifp;
+       struct brcmf_fweh_info *fweh;
+       struct brcmf_fweh_queue_item *event;
+       int err = 0;
+       struct brcmf_event_msg_be *emsg_be;
+       struct brcmf_event_msg emsg;
+
+       fweh = container_of(work, struct brcmf_fweh_info, event_work);
+       drvr = container_of(fweh, struct brcmf_pub, fweh);
+
+       while ((event = brcmf_fweh_dequeue_event(fweh))) {
+               ifp = drvr->iflist[event->ifidx];
+
+               brcmf_dbg(EVENT, "event %s (%u) ifidx %u bsscfg %u addr %pM:\n",
+                         brcmf_fweh_event_name(event->code), event->code,
+                         event->emsg.ifidx, event->emsg.bsscfgidx,
+                         event->emsg.addr);
+
+               /* convert event message */
+               emsg_be = &event->emsg;
+               emsg.version = be16_to_cpu(emsg_be->version);
+               emsg.flags = be16_to_cpu(emsg_be->flags);
+               emsg.event_code = event->code;
+               emsg.status = be32_to_cpu(emsg_be->status);
+               emsg.reason = be32_to_cpu(emsg_be->reason);
+               emsg.auth_type = be32_to_cpu(emsg_be->auth_type);
+               emsg.datalen = be32_to_cpu(emsg_be->datalen);
+               memcpy(emsg.addr, emsg_be->addr, ETH_ALEN);
+               memcpy(emsg.ifname, emsg_be->ifname, sizeof(emsg.ifname));
+               emsg.ifidx = emsg_be->ifidx;
+               emsg.bsscfgidx = emsg_be->bsscfgidx;
+
+               brcmf_dbg(EVENT, "  version %u flags %u status %u reason %u\n",
+                         emsg.version, emsg.flags, emsg.status, emsg.reason);
+               brcmf_dbg_hex_dump(BRCMF_EVENT_ON(), event->data,
+                                  min_t(u32, emsg.datalen, 64),
+                                  "appended:");
+
+               /* special handling of interface event */
+               if (event->code == BRCMF_E_IF) {
+                       brcmf_fweh_handle_if_event(drvr, &emsg, event->data);
+                       goto event_free;
+               }
+
+               err = brcmf_fweh_call_event_handler(ifp, event->code, &emsg,
+                                                   event->data);
+               if (err) {
+                       brcmf_dbg(ERROR, "event handler failed (%d)\n",
+                                 event->code);
+                       err = 0;
+               }
+event_free:
+               kfree(event);
+       }
+}
+
+/**
+ * brcmf_fweh_attach() - initialize firmware event handling.
+ *
+ * @drvr: driver information object.
+ */
+void brcmf_fweh_attach(struct brcmf_pub *drvr)
+{
+       struct brcmf_fweh_info *fweh = &drvr->fweh;
+       INIT_WORK(&fweh->event_work, brcmf_fweh_event_worker);
+       spin_lock_init(&fweh->evt_q_lock);
+       INIT_LIST_HEAD(&fweh->event_q);
+}
+
+/**
+ * brcmf_fweh_detach() - cleanup firmware event handling.
+ *
+ * @drvr: driver information object.
+ */
+void brcmf_fweh_detach(struct brcmf_pub *drvr)
+{
+       struct brcmf_fweh_info *fweh = &drvr->fweh;
+       struct brcmf_if *ifp = drvr->iflist[0];
+       s8 eventmask[BRCMF_EVENTING_MASK_LEN];
+
+       if (ifp) {
+               /* clear all events */
+               memset(eventmask, 0, BRCMF_EVENTING_MASK_LEN);
+               (void)brcmf_fil_iovar_data_set(ifp, "event_msgs",
+                                              eventmask,
+                                              BRCMF_EVENTING_MASK_LEN);
+       }
+       /* cancel the worker */
+       cancel_work_sync(&fweh->event_work);
+       WARN_ON(!list_empty(&fweh->event_q));
+       memset(fweh->evt_handler, 0, sizeof(fweh->evt_handler));
+}
+
+/**
+ * brcmf_fweh_register() - register handler for given event code.
+ *
+ * @drvr: driver information object.
+ * @code: event code.
+ * @handler: handler for the given event code.
+ */
+int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
+                       brcmf_fweh_handler_t handler)
+{
+       if (drvr->fweh.evt_handler[code]) {
+               brcmf_dbg(ERROR, "event code %d already registered\n", code);
+               return -ENOSPC;
+       }
+       drvr->fweh.evt_handler[code] = handler;
+       brcmf_dbg(TRACE, "event handler registered for %s\n",
+                 brcmf_fweh_event_name(code));
+       return 0;
+}
+
+/**
+ * brcmf_fweh_unregister() - remove handler for given code.
+ *
+ * @drvr: driver information object.
+ * @code: event code.
+ */
+void brcmf_fweh_unregister(struct brcmf_pub *drvr,
+                          enum brcmf_fweh_event_code code)
+{
+       brcmf_dbg(TRACE, "event handler cleared for %s\n",
+                 brcmf_fweh_event_name(code));
+       drvr->fweh.evt_handler[code] = NULL;
+}
+
+/**
+ * brcmf_fweh_activate_events() - enables firmware events registered.
+ *
+ * @ifp: primary interface object.
+ */
+int brcmf_fweh_activate_events(struct brcmf_if *ifp)
+{
+       int i, err;
+       s8 eventmask[BRCMF_EVENTING_MASK_LEN];
+
+       for (i = 0; i < BRCMF_E_LAST; i++) {
+               if (ifp->drvr->fweh.evt_handler[i]) {
+                       brcmf_dbg(EVENT, "enable event %s\n",
+                                 brcmf_fweh_event_name(i));
+                       setbit(eventmask, i);
+               }
+       }
+
+       /* want to handle IF event as well */
+       brcmf_dbg(EVENT, "enable event IF\n");
+       setbit(eventmask, BRCMF_E_IF);
+
+       err = brcmf_fil_iovar_data_set(ifp, "event_msgs",
+                                      eventmask, BRCMF_EVENTING_MASK_LEN);
+       if (err)
+               brcmf_dbg(ERROR, "Set event_msgs error (%d)\n", err);
+
+       return err;
+}
+
+/**
+ * brcmf_fweh_process_event() - process skb as firmware event.
+ *
+ * @drvr: driver information object.
+ * @event_packet: event packet to process.
+ * @ifidx: index of the firmware interface (may change).
+ *
+ * If the packet buffer contains a firmware event message it will
+ * dispatch the event to a registered handler (using worker).
+ */
+void brcmf_fweh_process_event(struct brcmf_pub *drvr,
+                             struct brcmf_event *event_packet, u8 *ifidx)
+{
+       enum brcmf_fweh_event_code code;
+       struct brcmf_fweh_info *fweh = &drvr->fweh;
+       struct brcmf_fweh_queue_item *event;
+       gfp_t alloc_flag = GFP_KERNEL;
+       void *data;
+       u32 datalen;
+
+       /* get event info */
+       code = get_unaligned_be32(&event_packet->msg.event_type);
+       datalen = get_unaligned_be32(&event_packet->msg.datalen);
+       *ifidx = event_packet->msg.ifidx;
+       data = &event_packet[1];
+
+       if (code >= BRCMF_E_LAST)
+               return;
+
+       if (code != BRCMF_E_IF && !fweh->evt_handler[code])
+               return;
+
+       if (in_interrupt())
+               alloc_flag = GFP_ATOMIC;
+
+       event = kzalloc(sizeof(*event) + datalen, alloc_flag);
+       if (!event)
+               return;
+
+       event->code = code;
+       event->ifidx = *ifidx;
+
+       /* use memcpy to get aligned event message */
+       memcpy(&event->emsg, &event_packet->msg, sizeof(event->emsg));
+       memcpy(event->data, data, datalen);
+       memcpy(event->ifaddr, event_packet->eth.h_dest, ETH_ALEN);
+
+       brcmf_fweh_queue_event(fweh, event);
+}
diff --git a/drivers/net/wireless/brcm80211/brcmfmac/fweh.h b/drivers/net/wireless/brcm80211/brcmfmac/fweh.h
new file mode 100644 (file)
index 0000000..b39246a
--- /dev/null
@@ -0,0 +1,207 @@
+/*
+ * Copyright (c) 2012 Broadcom Corporation
+ *
+ * Permission to use, copy, modify, and/or distribute this software for any
+ * purpose with or without fee is hereby granted, provided that the above
+ * copyright notice and this permission notice appear in all copies.
+ *
+ * THE SOFTWARE IS PROVIDED "AS IS" AND THE AUTHOR DISCLAIMS ALL WARRANTIES
+ * WITH REGARD TO THIS SOFTWARE INCLUDING ALL IMPLIED WARRANTIES OF
+ * MERCHANTABILITY AND FITNESS. IN NO EVENT SHALL THE AUTHOR BE LIABLE FOR ANY
+ * SPECIAL, DIRECT, INDIRECT, OR CONSEQUENTIAL DAMAGES OR ANY DAMAGES
+ * WHATSOEVER RESULTING FROM LOSS OF USE, DATA OR PROFITS, WHETHER IN AN ACTION
+ * OF CONTRACT, NEGLIGENCE OR OTHER TORTIOUS ACTION, ARISING OUT OF OR IN
+ * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
+ */
+
+
+#ifndef FWEH_H_
+#define FWEH_H_
+
+#include <asm/unaligned.h>
+#include <linux/skbuff.h>
+#include <linux/if_ether.h>
+#include <linux/if.h>
+
+/* formward declarations */
+struct brcmf_pub;
+struct brcmf_if;
+struct brcmf_cfg80211_info;
+struct brcmf_event;
+
+/* firmware event codes sent by the dongle */
+enum brcmf_fweh_event_code {
+       BRCMF_E_SET_SSID                = 0,
+       BRCMF_E_JOIN                    = 1,
+       BRCMF_E_START                   = 2,
+       BRCMF_E_AUTH                    = 3,
+       BRCMF_E_AUTH_IND                = 4,
+       BRCMF_E_DEAUTH                  = 5,
+       BRCMF_E_DEAUTH_IND              = 6,
+       BRCMF_E_ASSOC                   = 7,
+       BRCMF_E_ASSOC_IND               = 8,
+       BRCMF_E_REASSOC                 = 9,
+       BRCMF_E_REASSOC_IND             = 10,
+       BRCMF_E_DISASSOC                = 11,
+       BRCMF_E_DISASSOC_IND            = 12,
+       BRCMF_E_QUIET_START             = 13,
+       BRCMF_E_QUIET_END               = 14,
+       BRCMF_E_BEACON_RX               = 15,
+       BRCMF_E_LINK                    = 16,
+       BRCMF_E_MIC_ERROR               = 17,
+       BRCMF_E_NDIS_LINK               = 18,
+       BRCMF_E_ROAM                    = 19,
+       BRCMF_E_TXFAIL                  = 20,
+       BRCMF_E_PMKID_CACHE             = 21,
+       BRCMF_E_RETROGRADE_TSF          = 22,
+       BRCMF_E_PRUNE                   = 23,
+       BRCMF_E_AUTOAUTH                = 24,
+       BRCMF_E_EAPOL_MSG               = 25,
+       BRCMF_E_SCAN_COMPLETE           = 26,
+       BRCMF_E_ADDTS_IND               = 27,
+       BRCMF_E_DELTS_IND               = 28,
+       BRCMF_E_BCNSENT_IND             = 29,
+       BRCMF_E_BCNRX_MSG               = 30,
+       BRCMF_E_BCNLOST_MSG             = 31,
+       BRCMF_E_ROAM_PREP               = 32,
+       BRCMF_E_PFN_NET_FOUND           = 33,
+       BRCMF_E_PFN_NET_LOST            = 34,
+       BRCMF_E_RESET_COMPLETE          = 35,
+       BRCMF_E_JOIN_START              = 36,
+       BRCMF_E_ROAM_START              = 37,
+       BRCMF_E_ASSOC_START             = 38,
+       BRCMF_E_IBSS_ASSOC              = 39,
+       BRCMF_E_RADIO                   = 40,
+       BRCMF_E_PSM_WATCHDOG            = 41,
+       BRCMF_E_PROBREQ_MSG             = 44,
+       BRCMF_E_SCAN_CONFIRM_IND        = 45,
+       BRCMF_E_PSK_SUP                 = 46,
+       BRCMF_E_COUNTRY_CODE_CHANGED    = 47,
+       BRCMF_E_EXCEEDED_MEDIUM_TIME    = 48,
+       BRCMF_E_ICV_ERROR               = 49,
+       BRCMF_E_UNICAST_DECODE_ERROR    = 50,
+       BRCMF_E_MULTICAST_DECODE_ERROR  = 51,
+       BRCMF_E_TRACE                   = 52,
+       BRCMF_E_IF                      = 54,
+       BRCMF_E_RSSI                    = 56,
+       BRCMF_E_PFN_SCAN_COMPLETE       = 57,
+       BRCMF_E_EXTLOG_MSG              = 58,
+       BRCMF_E_ACTION_FRAME            = 59,
+       BRCMF_E_ACTION_FRAME_COMPLETE   = 60,
+       BRCMF_E_PRE_ASSOC_IND           = 61,
+       BRCMF_E_PRE_REASSOC_IND         = 62,
+       BRCMF_E_CHANNEL_ADOPTED         = 63,
+       BRCMF_E_AP_STARTED              = 64,
+       BRCMF_E_DFS_AP_STOP             = 65,
+       BRCMF_E_DFS_AP_RESUME           = 66,
+       BRCMF_E_ESCAN_RESULT            = 69,
+       BRCMF_E_ACTION_FRAME_OFF_CHAN_COMPLETE  = 70,
+       BRCMF_E_DCS_REQUEST             = 73,
+       BRCMF_E_FIFO_CREDIT_MAP         = 74,
+       BRCMF_E_LAST
+};
+
+/* flags field values in struct brcmf_event_msg */
+#define BRCMF_EVENT_MSG_LINK           0x01
+#define BRCMF_EVENT_MSG_FLUSHTXQ       0x02
+#define BRCMF_EVENT_MSG_GROUP          0x04
+
+/**
+ * definitions for event packet validation.
+ */
+#define BRCMF_EVENT_OUI_OFFSET         19
+#define BRCM_OUI                       "\x00\x10\x18"
+#define DOT11_OUI_LEN                  3
+#define BCMILCP_BCM_SUBTYPE_EVENT      1
+
+
+/**
+ * struct brcmf_event_msg - firmware event message.
+ *
+ * @version: version information.
+ * @flags: event flags.
+ * @event_code: firmware event code.
+ * @status: status information.
+ * @reason: reason code.
+ * @auth_type: authentication type.
+ * @datalen: lenght of event data buffer.
+ * @addr: ether address.
+ * @ifname: interface name.
+ * @ifidx: interface index.
+ * @bsscfgidx: bsscfg index.
+ */
+struct brcmf_event_msg {
+       u16 version;
+       u16 flags;
+       u32 event_code;
+       u32 status;
+       u32 reason;
+       s32 auth_type;
+       u32 datalen;
+       u8 addr[ETH_ALEN];
+       char ifname[IFNAMSIZ];
+       u8 ifidx;
+       u8 bsscfgidx;
+};
+
+typedef int (*brcmf_fweh_handler_t)(struct brcmf_if *ifp,
+                                   const struct brcmf_event_msg *evtmsg,
+                                   void *data);
+
+/**
+ * struct brcmf_fweh_info - firmware event handling information.
+ *
+ * @event_work: event worker.
+ * @evt_q_lock: lock for event queue protection.
+ * @event_q: event queue.
+ * @evt_handler: registered event handlers.
+ */
+struct brcmf_fweh_info {
+       struct work_struct event_work;
+       struct spinlock evt_q_lock;
+       struct list_head event_q;
+       int (*evt_handler[BRCMF_E_LAST])(struct brcmf_if *ifp,
+                                        const struct brcmf_event_msg *evtmsg,
+                                        void *data);
+};
+
+void brcmf_fweh_attach(struct brcmf_pub *drvr);
+void brcmf_fweh_detach(struct brcmf_pub *drvr);
+int brcmf_fweh_register(struct brcmf_pub *drvr, enum brcmf_fweh_event_code code,
+                       int (*handler)(struct brcmf_if *ifp,
+                                      const struct brcmf_event_msg *evtmsg,
+                                      void *data));
+void brcmf_fweh_unregister(struct brcmf_pub *drvr,
+                          enum brcmf_fweh_event_code code);
+int brcmf_fweh_activate_events(struct brcmf_if *ifp);
+void brcmf_fweh_process_event(struct brcmf_pub *drvr,
+                             struct brcmf_event *event_packet, u8 *ifidx);
+
+static inline void brcmf_fweh_process_skb(struct brcmf_pub *drvr,
+                                         struct sk_buff *skb, u8 *ifidx)
+{
+       struct brcmf_event *event_packet;
+       u8 *data;
+       u16 usr_stype;
+
+       /* only process events when protocol matches */
+       if (skb->protocol != cpu_to_be16(ETH_P_LINK_CTL))
+               return;
+
+       /* check for BRCM oui match */
+       event_packet = (struct brcmf_event *)skb_mac_header(skb);
+       data = (u8 *)event_packet;
+       data += BRCMF_EVENT_OUI_OFFSET;
+       if (memcmp(BRCM_OUI, data, DOT11_OUI_LEN))
+               return;
+
+       /* final match on usr_subtype */
+       data += DOT11_OUI_LEN;
+       usr_stype = get_unaligned_be16(data);
+       if (usr_stype != BCMILCP_BCM_SUBTYPE_EVENT)
+               return;
+
+       brcmf_fweh_process_event(drvr, event_packet, ifidx);
+}
+
+#endif /* FWEH_H_ */
index 4b272c3d237c9d07119a37b5eccd56740d7d0e8e..51a14505197a98f2a8e80e50075c49896bc288a1 100644 (file)
@@ -20,7 +20,6 @@
 
 #include <linux/kernel.h>
 #include <linux/netdevice.h>
-#include <defs.h>
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 #include "dhd.h"
 #include "fwil.h"
 
 
+#define MAX_HEX_DUMP_LEN       64
+
+
 static s32
 brcmf_fil_cmd_data(struct brcmf_if *ifp, u32 cmd, void *data, u32 len, bool set)
 {
        struct brcmf_pub *drvr = ifp->drvr;
        s32 err;
 
-       if (drvr->bus_if->state == BRCMF_BUS_DOWN) {
+       if (drvr->bus_if->state != BRCMF_BUS_DATA) {
                brcmf_dbg(ERROR, "bus is down. we have nothing to do.\n");
                return -EIO;
        }
@@ -64,7 +66,8 @@ brcmf_fil_cmd_data_set(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
        mutex_lock(&ifp->drvr->proto_block);
 
        brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
-       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
 
        err = brcmf_fil_cmd_data(ifp, cmd, data, len, true);
        mutex_unlock(&ifp->drvr->proto_block);
@@ -81,7 +84,8 @@ brcmf_fil_cmd_data_get(struct brcmf_if *ifp, u32 cmd, void *data, u32 len)
        err = brcmf_fil_cmd_data(ifp, cmd, data, len, false);
 
        brcmf_dbg(FIL, "cmd=%d, len=%d\n", cmd, len);
-       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
 
        mutex_unlock(&ifp->drvr->proto_block);
 
@@ -147,7 +151,8 @@ brcmf_fil_iovar_data_set(struct brcmf_if *ifp, char *name, void *data,
        mutex_lock(&drvr->proto_block);
 
        brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
-       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
 
        buflen = brcmf_create_iovar(name, data, len, drvr->proto_buf,
                                    sizeof(drvr->proto_buf));
@@ -186,7 +191,8 @@ brcmf_fil_iovar_data_get(struct brcmf_if *ifp, char *name, void *data,
        }
 
        brcmf_dbg(FIL, "name=%s, len=%d\n", name, len);
-       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
 
        mutex_unlock(&drvr->proto_block);
        return err;
@@ -268,7 +274,8 @@ brcmf_fil_bsscfg_data_set(struct brcmf_if *ifp, char *name,
        mutex_lock(&drvr->proto_block);
 
        brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
-       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
 
        buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
                                     drvr->proto_buf, sizeof(drvr->proto_buf));
@@ -294,7 +301,7 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
 
        mutex_lock(&drvr->proto_block);
 
-       buflen = brcmf_create_bsscfg(ifp->bssidx, name, NULL, len,
+       buflen = brcmf_create_bsscfg(ifp->bssidx, name, data, len,
                                     drvr->proto_buf, sizeof(drvr->proto_buf));
        if (buflen) {
                err = brcmf_fil_cmd_data(ifp, BRCMF_C_GET_VAR, drvr->proto_buf,
@@ -306,7 +313,8 @@ brcmf_fil_bsscfg_data_get(struct brcmf_if *ifp, char *name,
                brcmf_dbg(ERROR, "Creating bsscfg failed\n");
        }
        brcmf_dbg(FIL, "bssidx=%d, name=%s, len=%d\n", ifp->bssidx, name, len);
-       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data, len, "data");
+       brcmf_dbg_hex_dump(BRCMF_FIL_ON(), data,
+                          min_t(uint, len, MAX_HEX_DUMP_LEN), "data");
 
        mutex_unlock(&drvr->proto_block);
        return err;
index 484a6e4f23a206dc6e341bd7ffde1c7d4cd45656..39a5baa92f217ef93aede25e77b90884751fa821 100644 (file)
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#include <linux/init.h>
 #include <linux/kernel.h>
 #include <linux/module.h>
-#include <linux/kthread.h>
-#include <linux/slab.h>
-#include <linux/skbuff.h>
-#include <linux/netdevice.h>
-#include <linux/spinlock.h>
-#include <linux/ethtool.h>
-#include <linux/fcntl.h>
-#include <linux/fs.h>
-#include <linux/uaccess.h>
 #include <linux/firmware.h>
 #include <linux/usb.h>
 #include <linux/vmalloc.h>
-#include <net/cfg80211.h>
 
-#include <defs.h>
 #include <brcmu_utils.h>
 #include <brcmu_wifi.h>
 #include <dhd_bus.h>
 
 #define IOCTL_RESP_TIMEOUT  2000
 
-#define BRCMF_USB_DLIMAGE_SPINWAIT     100     /* in unit of ms */
-#define BRCMF_USB_DLIMAGE_LIMIT                500     /* spinwait limit (ms) */
+#define BRCMF_USB_RESET_GETVER_SPINWAIT        100     /* in unit of ms */
+#define BRCMF_USB_RESET_GETVER_LOOP_CNT        10
 
 #define BRCMF_POSTBOOT_ID              0xA123  /* ID to detect if dongle
                                                   has boot up */
-#define BRCMF_USB_RESETCFG_SPINWAIT    1       /* wait after resetcfg (ms) */
-
 #define BRCMF_USB_NRXQ 50
 #define BRCMF_USB_NTXQ 50
 
 #define BRCMF_USB_43236_FW_NAME        "brcm/brcmfmac43236b.bin"
 #define BRCMF_USB_43242_FW_NAME        "brcm/brcmfmac43242a.bin"
 
-enum usbdev_suspend_state {
-       USBOS_SUSPEND_STATE_DEVICE_ACTIVE = 0, /* Device is busy, won't allow
-                                                 suspend */
-       USBOS_SUSPEND_STATE_SUSPEND_PENDING,    /* Device is idle, can be
-                                                * suspended. Wating PM to
-                                                * suspend the device
-                                                */
-       USBOS_SUSPEND_STATE_SUSPENDED   /* Device suspended */
-};
-
 struct brcmf_usb_image {
        struct list_head list;
        s8 *fwname;
@@ -99,10 +75,8 @@ struct brcmf_usbdev_info {
        struct list_head rx_postq;
        struct list_head tx_freeq;
        struct list_head tx_postq;
-       enum usbdev_suspend_state suspend_state;
        uint rx_pipe, tx_pipe, intr_pipe, rx_pipe2;
 
-       bool activity;
        int rx_low_watermark;
        int tx_low_watermark;
        int tx_high_watermark;
@@ -170,6 +144,7 @@ static void brcmf_usb_ioctl_resp_wake(struct brcmf_usbdev_info *devinfo)
 static void
 brcmf_usb_ctl_complete(struct brcmf_usbdev_info *devinfo, int type, int status)
 {
+       brcmf_dbg(USB, "Enter, status=%d\n", status);
 
        if (unlikely(devinfo == NULL))
                return;
@@ -197,6 +172,7 @@ brcmf_usb_ctlread_complete(struct urb *urb)
        struct brcmf_usbdev_info *devinfo =
                (struct brcmf_usbdev_info *)urb->context;
 
+       brcmf_dbg(USB, "Enter\n");
        devinfo->ctl_urb_actual_length = urb->actual_length;
        brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_READ,
                urb->status);
@@ -208,33 +184,22 @@ brcmf_usb_ctlwrite_complete(struct urb *urb)
        struct brcmf_usbdev_info *devinfo =
                (struct brcmf_usbdev_info *)urb->context;
 
+       brcmf_dbg(USB, "Enter\n");
        brcmf_usb_ctl_complete(devinfo, BRCMF_USB_CBCTL_WRITE,
                urb->status);
 }
 
-static int brcmf_usb_pnp(struct brcmf_usbdev_info *devinfo, uint state)
-{
-       return 0;
-}
-
 static int
 brcmf_usb_send_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
 {
        int ret;
        u16 size;
 
+       brcmf_dbg(USB, "Enter\n");
        if (devinfo == NULL || buf == NULL ||
            len == 0 || devinfo->ctl_urb == NULL)
                return -EINVAL;
 
-       /* If the USB/HSIC bus in sleep state, wake it up */
-       if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED)
-               if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
-                       brcmf_dbg(ERROR, "Could not Resume the bus!\n");
-                       return -EIO;
-               }
-
-       devinfo->activity = true;
        size = len;
        devinfo->ctl_write.wLength = cpu_to_le16p(&size);
        devinfo->ctl_urb->transfer_buffer_length = size;
@@ -262,6 +227,7 @@ brcmf_usb_recv_ctl(struct brcmf_usbdev_info *devinfo, u8 *buf, int len)
        int ret;
        u16 size;
 
+       brcmf_dbg(USB, "Enter\n");
        if ((devinfo == NULL) || (buf == NULL) || (len == 0)
                || (devinfo->ctl_urb == NULL))
                return -EINVAL;
@@ -295,10 +261,9 @@ static int brcmf_usb_tx_ctlpkt(struct device *dev, u8 *buf, u32 len)
        int timeout = 0;
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
 
-       if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
-               /* TODO: handle suspend/resume */
+       brcmf_dbg(USB, "Enter\n");
+       if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
                return -EIO;
-       }
 
        if (test_and_set_bit(0, &devinfo->ctl_op))
                return -EIO;
@@ -325,10 +290,10 @@ static int brcmf_usb_rx_ctlpkt(struct device *dev, u8 *buf, u32 len)
        int timeout = 0;
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
 
-       if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
-               /* TODO: handle suspend/resume */
+       brcmf_dbg(USB, "Enter\n");
+       if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
                return -EIO;
-       }
+
        if (test_and_set_bit(0, &devinfo->ctl_op))
                return -EIO;
 
@@ -453,6 +418,8 @@ static void brcmf_usb_tx_complete(struct urb *urb)
        struct brcmf_usbreq *req = (struct brcmf_usbreq *)urb->context;
        struct brcmf_usbdev_info *devinfo = req->devinfo;
 
+       brcmf_dbg(USB, "Enter, urb->status=%d, skb=%p\n", urb->status,
+                 req->skb);
        brcmf_usb_del_fromq(devinfo, req);
        if (urb->status == 0)
                devinfo->bus_pub.bus->dstats.tx_packets++;
@@ -478,6 +445,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
        struct sk_buff *skb;
        int ifidx = 0;
 
+       brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
        brcmf_usb_del_fromq(devinfo, req);
        skb = req->skb;
        req->skb = NULL;
@@ -491,7 +459,7 @@ static void brcmf_usb_rx_complete(struct urb *urb)
                return;
        }
 
-       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP) {
+       if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
                skb_put(skb, urb->actual_length);
                if (brcmf_proto_hdrpull(devinfo->dev, &ifidx, skb) != 0) {
                        brcmf_dbg(ERROR, "rx protocol error\n");
@@ -544,8 +512,8 @@ static void brcmf_usb_rx_fill_all(struct brcmf_usbdev_info *devinfo)
 {
        struct brcmf_usbreq *req;
 
-       if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
-               brcmf_dbg(ERROR, "bus is not up\n");
+       if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP) {
+               brcmf_dbg(ERROR, "bus is not up=%d\n", devinfo->bus_pub.state);
                return;
        }
        while ((req = brcmf_usb_deq(devinfo, &devinfo->rx_freeq, NULL)) != NULL)
@@ -558,29 +526,24 @@ brcmf_usb_state_change(struct brcmf_usbdev_info *devinfo, int state)
        struct brcmf_bus *bcmf_bus = devinfo->bus_pub.bus;
        int old_state;
 
+       brcmf_dbg(USB, "Enter, current state=%d, new state=%d\n",
+                 devinfo->bus_pub.state, state);
 
        if (devinfo->bus_pub.state == state)
                return;
 
        old_state = devinfo->bus_pub.state;
-       brcmf_dbg(TRACE, "dbus state change from %d to to %d\n",
-                 old_state, state);
-
-       /* Don't update state if it's PnP firmware re-download */
-       if (state != BCMFMAC_USB_STATE_PNP_FWDL) /* TODO */
-               devinfo->bus_pub.state = state;
-
-       if ((old_state  == BCMFMAC_USB_STATE_SLEEP)
-               && (state == BCMFMAC_USB_STATE_UP)) {
-               brcmf_usb_rx_fill_all(devinfo);
-       }
+       devinfo->bus_pub.state = state;
 
        /* update state of upper layer */
-       if (state == BCMFMAC_USB_STATE_DOWN) {
-               brcmf_dbg(INFO, "DBUS is down\n");
+       if (state == BRCMFMAC_USB_STATE_DOWN) {
+               brcmf_dbg(USB, "DBUS is down\n");
                bcmf_bus->state = BRCMF_BUS_DOWN;
+       } else if (state == BRCMFMAC_USB_STATE_UP) {
+               brcmf_dbg(USB, "DBUS is up\n");
+               bcmf_bus->state = BRCMF_BUS_DATA;
        } else {
-               brcmf_dbg(INFO, "DBUS current state=%d\n", state);
+               brcmf_dbg(USB, "DBUS current state=%d\n", state);
        }
 }
 
@@ -589,30 +552,32 @@ brcmf_usb_intr_complete(struct urb *urb)
 {
        struct brcmf_usbdev_info *devinfo =
                        (struct brcmf_usbdev_info *)urb->context;
-       bool killed;
+       int err;
+
+       brcmf_dbg(USB, "Enter, urb->status=%d\n", urb->status);
 
        if (devinfo == NULL)
                return;
 
        if (unlikely(urb->status)) {
-               if (devinfo->suspend_state ==
-                       USBOS_SUSPEND_STATE_SUSPEND_PENDING)
-                       killed = true;
-
-               if ((urb->status == -ENOENT && (!killed))
-                       || urb->status == -ESHUTDOWN ||
-                       urb->status == -ENODEV) {
-                       brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
+               if (urb->status == -ENOENT ||
+                   urb->status == -ESHUTDOWN ||
+                   urb->status == -ENODEV) {
+                       brcmf_usb_state_change(devinfo,
+                                              BRCMFMAC_USB_STATE_DOWN);
                }
        }
 
-       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN) {
+       if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN) {
                brcmf_dbg(ERROR, "intr cb when DBUS down, ignoring\n");
                return;
        }
 
-       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
-               usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
+       if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP) {
+               err = usb_submit_urb(devinfo->intr_urb, GFP_ATOMIC);
+               if (err)
+                       brcmf_dbg(ERROR, "usb_submit_urb, err=%d\n", err);
+       }
 }
 
 static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
@@ -621,10 +586,9 @@ static int brcmf_usb_tx(struct device *dev, struct sk_buff *skb)
        struct brcmf_usbreq  *req;
        int ret;
 
-       if (devinfo->bus_pub.state != BCMFMAC_USB_STATE_UP) {
-               /* TODO: handle suspend/resume */
+       brcmf_dbg(USB, "Enter, skb=%p\n", skb);
+       if (devinfo->bus_pub.state != BRCMFMAC_USB_STATE_UP)
                return -EIO;
-       }
 
        req = brcmf_usb_deq(devinfo, &devinfo->tx_freeq,
                                        &devinfo->tx_freecount);
@@ -664,25 +628,16 @@ static int brcmf_usb_up(struct device *dev)
 {
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
        u16 ifnum;
+       int ret;
 
-       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_UP)
+       brcmf_dbg(USB, "Enter\n");
+       if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_UP)
                return 0;
 
-       /* If the USB/HSIC bus in sleep state, wake it up */
-       if (devinfo->suspend_state == USBOS_SUSPEND_STATE_SUSPENDED) {
-               if (brcmf_usb_pnp(devinfo, BCMFMAC_USB_PNP_RESUME) != 0) {
-                       brcmf_dbg(ERROR, "Could not Resume the bus!\n");
-                       return -EIO;
-               }
-       }
-       devinfo->activity = true;
-
        /* Success, indicate devinfo is fully up */
-       brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_UP);
+       brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_UP);
 
        if (devinfo->intr_urb) {
-               int ret;
-
                usb_fill_int_urb(devinfo->intr_urb, devinfo->usbdev,
                        devinfo->intr_pipe,
                        &devinfo->intr,
@@ -727,14 +682,14 @@ static void brcmf_usb_down(struct device *dev)
 {
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(dev);
 
+       brcmf_dbg(USB, "Enter\n");
        if (devinfo == NULL)
                return;
 
-       brcmf_dbg(TRACE, "enter\n");
-       if (devinfo->bus_pub.state == BCMFMAC_USB_STATE_DOWN)
+       if (devinfo->bus_pub.state == BRCMFMAC_USB_STATE_DOWN)
                return;
 
-       brcmf_usb_state_change(devinfo, BCMFMAC_USB_STATE_DOWN);
+       brcmf_usb_state_change(devinfo, BRCMFMAC_USB_STATE_DOWN);
        if (devinfo->intr_urb)
                usb_kill_urb(devinfo->intr_urb);
 
@@ -808,27 +763,25 @@ brcmf_usb_dlneeded(struct brcmf_usbdev_info *devinfo)
        struct bootrom_id_le id;
        u32 chipid, chiprev;
 
-       brcmf_dbg(TRACE, "enter\n");
+       brcmf_dbg(USB, "Enter\n");
 
        if (devinfo == NULL)
                return false;
 
        /* Check if firmware downloaded already by querying runtime ID */
        id.chip = cpu_to_le32(0xDEAD);
-       brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
-               sizeof(struct bootrom_id_le));
+       brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
 
        chipid = le32_to_cpu(id.chip);
        chiprev = le32_to_cpu(id.chiprev);
 
        if ((chipid & 0x4300) == 0x4300)
-               brcmf_dbg(INFO, "chip %x rev 0x%x\n", chipid, chiprev);
+               brcmf_dbg(USB, "chip %x rev 0x%x\n", chipid, chiprev);
        else
-               brcmf_dbg(INFO, "chip %d rev 0x%x\n", chipid, chiprev);
+               brcmf_dbg(USB, "chip %d rev 0x%x\n", chipid, chiprev);
        if (chipid == BRCMF_POSTBOOT_ID) {
-               brcmf_dbg(INFO, "firmware already downloaded\n");
-               brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
-                       sizeof(struct bootrom_id_le));
+               brcmf_dbg(USB, "firmware already downloaded\n");
+               brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id));
                return false;
        } else {
                devinfo->bus_pub.devid = chipid;
@@ -841,38 +794,29 @@ static int
 brcmf_usb_resetcfg(struct brcmf_usbdev_info *devinfo)
 {
        struct bootrom_id_le id;
-       u16 wait = 0, wait_time;
+       u32 loop_cnt;
 
-       brcmf_dbg(TRACE, "enter\n");
-
-       if (devinfo == NULL)
-               return -EINVAL;
+       brcmf_dbg(USB, "Enter\n");
 
-       /* Give dongle chance to boot */
-       wait_time = BRCMF_USB_DLIMAGE_SPINWAIT;
-       while (wait < BRCMF_USB_DLIMAGE_LIMIT) {
-               mdelay(wait_time);
-               wait += wait_time;
+       loop_cnt = 0;
+       do {
+               mdelay(BRCMF_USB_RESET_GETVER_SPINWAIT);
+               loop_cnt++;
                id.chip = cpu_to_le32(0xDEAD);       /* Get the ID */
-               brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id,
-                       sizeof(struct bootrom_id_le));
+               brcmf_usb_dl_cmd(devinfo, DL_GETVER, &id, sizeof(id));
                if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID))
                        break;
-       }
+       } while (loop_cnt < BRCMF_USB_RESET_GETVER_LOOP_CNT);
 
        if (id.chip == cpu_to_le32(BRCMF_POSTBOOT_ID)) {
-               brcmf_dbg(INFO, "download done %d ms postboot chip 0x%x/rev 0x%x\n",
-                         wait, le32_to_cpu(id.chip), le32_to_cpu(id.chiprev));
-
-               brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id,
-                       sizeof(struct bootrom_id_le));
+               brcmf_dbg(USB, "postboot chip 0x%x/rev 0x%x\n",
+                         le32_to_cpu(id.chip), le32_to_cpu(id.chiprev));
 
-               /* XXX this wait may not be necessary */
-               mdelay(BRCMF_USB_RESETCFG_SPINWAIT);
+               brcmf_usb_dl_cmd(devinfo, DL_RESETCFG, &id, sizeof(id));
                return 0;
        } else {
                brcmf_dbg(ERROR, "Cannot talk to Dongle. Firmware is not UP, %d ms\n",
-                         wait);
+                         BRCMF_USB_RESET_GETVER_SPINWAIT * loop_cnt);
                return -EINVAL;
        }
 }
@@ -911,7 +855,8 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
        struct rdl_state_le state;
        u32 rdlstate, rdlbytes;
        int err = 0;
-       brcmf_dbg(TRACE, "fw %p, len %d\n", fw, fwlen);
+
+       brcmf_dbg(USB, "Enter, fw %p, len %d\n", fw, fwlen);
 
        bulkchunk = kmalloc(RDL_CHUNK, GFP_ATOMIC);
        if (bulkchunk == NULL) {
@@ -986,7 +931,7 @@ brcmf_usb_dl_writeimage(struct brcmf_usbdev_info *devinfo, u8 *fw, int fwlen)
 
 fail:
        kfree(bulkchunk);
-       brcmf_dbg(TRACE, "err=%d\n", err);
+       brcmf_dbg(USB, "Exit, err=%d\n", err);
        return err;
 }
 
@@ -994,7 +939,7 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)
 {
        int err;
 
-       brcmf_dbg(TRACE, "enter\n");
+       brcmf_dbg(USB, "Enter\n");
 
        if (devinfo == NULL)
                return -EINVAL;
@@ -1004,10 +949,10 @@ static int brcmf_usb_dlstart(struct brcmf_usbdev_info *devinfo, u8 *fw, int len)
 
        err = brcmf_usb_dl_writeimage(devinfo, fw, len);
        if (err == 0)
-               devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_DONE;
+               devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_DONE;
        else
-               devinfo->bus_pub.state = BCMFMAC_USB_STATE_DL_PENDING;
-       brcmf_dbg(TRACE, "exit: err=%d\n", err);
+               devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DL_FAIL;
+       brcmf_dbg(USB, "Exit, err=%d\n", err);
 
        return err;
 }
@@ -1016,7 +961,7 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
 {
        struct rdl_state_le state;
 
-       brcmf_dbg(TRACE, "enter\n");
+       brcmf_dbg(USB, "Enter\n");
        if (!devinfo)
                return -EINVAL;
 
@@ -1039,7 +984,7 @@ static int brcmf_usb_dlrun(struct brcmf_usbdev_info *devinfo)
                brcmf_dbg(ERROR, "Dongle not runnable\n");
                return -EINVAL;
        }
-       brcmf_dbg(TRACE, "exit\n");
+       brcmf_dbg(USB, "Exit\n");
        return 0;
 }
 
@@ -1066,7 +1011,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
        int devid, chiprev;
        int err;
 
-       brcmf_dbg(TRACE, "enter\n");
+       brcmf_dbg(USB, "Enter\n");
        if (devinfo == NULL)
                return -ENODEV;
 
@@ -1094,7 +1039,7 @@ brcmf_usb_fw_download(struct brcmf_usbdev_info *devinfo)
 
 static void brcmf_usb_detach(struct brcmf_usbdev_info *devinfo)
 {
-       brcmf_dbg(TRACE, "devinfo %p\n", devinfo);
+       brcmf_dbg(USB, "Enter, devinfo %p\n", devinfo);
 
        /* free the URBS */
        brcmf_usb_free_q(&devinfo->rx_freeq, false);
@@ -1129,6 +1074,7 @@ static int check_file(const u8 *headers)
        struct trx_header_le *trx;
        int actual_len = -1;
 
+       brcmf_dbg(USB, "Enter\n");
        /* Extract trx header */
        trx = (struct trx_header_le *) headers;
        if (trx->magic != cpu_to_le32(TRX_MAGIC))
@@ -1150,6 +1096,7 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
        struct brcmf_usb_image *fw_image;
        int err;
 
+       brcmf_dbg(USB, "Enter\n");
        switch (devinfo->bus_pub.devid) {
        case 43143:
                fwname = BRCMF_USB_43143_FW_NAME;
@@ -1166,7 +1113,7 @@ static int brcmf_usb_get_fw(struct brcmf_usbdev_info *devinfo)
                return -EINVAL;
                break;
        }
-
+       brcmf_dbg(USB, "Loading FW %s\n", fwname);
        list_for_each_entry(fw_image, &fw_image_list, list) {
                if (fw_image->fwname == fwname) {
                        devinfo->image = fw_image->image;
@@ -1211,10 +1158,13 @@ static
 struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
                                      int nrxq, int ntxq)
 {
+       brcmf_dbg(USB, "Enter\n");
+
        devinfo->bus_pub.nrxq = nrxq;
        devinfo->rx_low_watermark = nrxq / 2;
        devinfo->bus_pub.devinfo = devinfo;
        devinfo->bus_pub.ntxq = ntxq;
+       devinfo->bus_pub.state = BRCMFMAC_USB_STATE_DOWN;
 
        /* flow control when too many tx urbs posted */
        devinfo->tx_low_watermark = ntxq / 4;
@@ -1263,7 +1213,7 @@ struct brcmf_usbdev *brcmf_usb_attach(struct brcmf_usbdev_info *devinfo,
        if (!brcmf_usb_dlneeded(devinfo))
                return &devinfo->bus_pub;
 
-       brcmf_dbg(TRACE, "start fw downloading\n");
+       brcmf_dbg(USB, "Start fw downloading\n");
        if (brcmf_usb_get_fw(devinfo))
                goto error;
 
@@ -1278,14 +1228,14 @@ error:
        return NULL;
 }
 
-static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
-                             const char *desc, u32 bustype, u32 hdrlen)
+static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo)
 {
        struct brcmf_bus *bus = NULL;
        struct brcmf_usbdev *bus_pub = NULL;
        int ret;
        struct device *dev = devinfo->dev;
 
+       brcmf_dbg(USB, "Enter\n");
        bus_pub = brcmf_usb_attach(devinfo, BRCMF_USB_NRXQ, BRCMF_USB_NTXQ);
        if (!bus_pub)
                return -ENODEV;
@@ -1302,14 +1252,13 @@ static int brcmf_usb_probe_cb(struct brcmf_usbdev_info *devinfo,
        bus->brcmf_bus_stop = brcmf_usb_down;
        bus->brcmf_bus_txctl = brcmf_usb_tx_ctlpkt;
        bus->brcmf_bus_rxctl = brcmf_usb_rx_ctlpkt;
-       bus->type = bustype;
        bus->bus_priv.usb = bus_pub;
        dev_set_drvdata(dev, bus);
 
        /* Attach to the common driver interface */
-       ret = brcmf_attach(hdrlen, dev);
+       ret = brcmf_attach(0, dev);
        if (ret) {
-               brcmf_dbg(ERROR, "dhd_attach failed\n");
+               brcmf_dbg(ERROR, "brcmf_attach failed\n");
                goto fail;
        }
 
@@ -1333,7 +1282,7 @@ brcmf_usb_disconnect_cb(struct brcmf_usbdev_info *devinfo)
 {
        if (!devinfo)
                return;
-       brcmf_dbg(TRACE, "enter: bus_pub %p\n", devinfo);
+       brcmf_dbg(USB, "Enter, bus_pub %p\n", devinfo);
 
        brcmf_detach(devinfo->dev);
        kfree(devinfo->bus_pub.bus);
@@ -1351,7 +1300,7 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
        u8 endpoint_num;
        struct brcmf_usbdev_info *devinfo;
 
-       brcmf_dbg(TRACE, "enter\n");
+       brcmf_dbg(USB, "Enter\n");
 
        devinfo = kzalloc(sizeof(*devinfo), GFP_ATOMIC);
        if (devinfo == NULL)
@@ -1452,11 +1401,11 @@ brcmf_usb_probe(struct usb_interface *intf, const struct usb_device_id *id)
        devinfo->interval = IFEPDESC(usb, CONTROL_IF, 0).bInterval;
 
        if (usb->speed == USB_SPEED_HIGH)
-               brcmf_dbg(INFO, "Broadcom high speed USB wireless device detected\n");
+               brcmf_dbg(USB, "Broadcom high speed USB wireless device detected\n");
        else
-               brcmf_dbg(INFO, "Broadcom full speed USB wireless device detected\n");
+               brcmf_dbg(USB, "Broadcom full speed USB wireless device detected\n");
 
-       ret = brcmf_usb_probe_cb(devinfo, "", USB_BUS, 0);
+       ret = brcmf_usb_probe_cb(devinfo);
        if (ret)
                goto fail;
 
@@ -1476,40 +1425,55 @@ brcmf_usb_disconnect(struct usb_interface *intf)
 {
        struct brcmf_usbdev_info *devinfo;
 
-       brcmf_dbg(TRACE, "enter\n");
+       brcmf_dbg(USB, "Enter\n");
        devinfo = (struct brcmf_usbdev_info *)usb_get_intfdata(intf);
        brcmf_usb_disconnect_cb(devinfo);
        kfree(devinfo);
+       brcmf_dbg(USB, "Exit\n");
 }
 
 /*
- *     only need to signal the bus being down and update the suspend state.
+ * only need to signal the bus being down and update the state.
  */
 static int brcmf_usb_suspend(struct usb_interface *intf, pm_message_t state)
 {
        struct usb_device *usb = interface_to_usbdev(intf);
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
 
-       brcmf_dbg(TRACE, "enter\n");
-       devinfo->bus_pub.state = BCMFMAC_USB_STATE_DOWN;
-       devinfo->suspend_state = USBOS_SUSPEND_STATE_SUSPENDED;
+       brcmf_dbg(USB, "Enter\n");
+       devinfo->bus_pub.state = BRCMFMAC_USB_STATE_SLEEP;
+       brcmf_detach(&usb->dev);
        return 0;
 }
 
 /*
- *     mark suspend state active and crank up the bus.
+ * (re-) start the bus.
  */
 static int brcmf_usb_resume(struct usb_interface *intf)
 {
        struct usb_device *usb = interface_to_usbdev(intf);
        struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
 
-       brcmf_dbg(TRACE, "enter\n");
-       devinfo->suspend_state = USBOS_SUSPEND_STATE_DEVICE_ACTIVE;
-       brcmf_bus_start(&usb->dev);
+       brcmf_dbg(USB, "Enter\n");
+       if (!brcmf_attach(0, devinfo->dev))
+               return brcmf_bus_start(&usb->dev);
+
        return 0;
 }
 
+static int brcmf_usb_reset_resume(struct usb_interface *intf)
+{
+       struct usb_device *usb = interface_to_usbdev(intf);
+       struct brcmf_usbdev_info *devinfo = brcmf_usb_get_businfo(&usb->dev);
+
+       brcmf_dbg(USB, "Enter\n");
+
+       if (!brcmf_usb_fw_download(devinfo))
+               return brcmf_usb_resume(intf);
+
+       return -EIO;
+}
+
 #define BRCMF_USB_VENDOR_ID_BROADCOM   0x0a5c
 #define BRCMF_USB_DEVICE_ID_43143      0xbd1e
 #define BRCMF_USB_DEVICE_ID_43236      0xbd17
@@ -1529,7 +1493,6 @@ MODULE_FIRMWARE(BRCMF_USB_43143_FW_NAME);
 MODULE_FIRMWARE(BRCMF_USB_43236_FW_NAME);
 MODULE_FIRMWARE(BRCMF_USB_43242_FW_NAME);
 
-/* TODO: suspend and resume entries */
 static struct usb_driver brcmf_usbdrvr = {
        .name = KBUILD_MODNAME,
        .probe = brcmf_usb_probe,
@@ -1537,6 +1500,7 @@ static struct usb_driver brcmf_usbdrvr = {
        .id_table = brcmf_usb_devid_table,
        .suspend = brcmf_usb_suspend,
        .resume = brcmf_usb_resume,
+       .reset_resume = brcmf_usb_reset_resume,
        .supports_autosuspend = 1,
        .disable_hub_initiated_lpm = 1,
 };
@@ -1554,12 +1518,14 @@ static void brcmf_release_fw(struct list_head *q)
 
 void brcmf_usb_exit(void)
 {
+       brcmf_dbg(USB, "Enter\n");
        usb_deregister(&brcmf_usbdrvr);
        brcmf_release_fw(&fw_image_list);
 }
 
 void brcmf_usb_init(void)
 {
+       brcmf_dbg(USB, "Enter\n");
        INIT_LIST_HEAD(&fw_image_list);
        usb_register(&brcmf_usbdrvr);
 }
index acfa5e89872fb8c8103ebb626beef5c0ba0064a2..f483a8c9945b1cc049eb2223039a522974dd61ea 100644 (file)
 #define BRCMFMAC_USB_H
 
 enum brcmf_usb_state {
-       BCMFMAC_USB_STATE_DL_PENDING,
-       BCMFMAC_USB_STATE_DL_DONE,
-       BCMFMAC_USB_STATE_UP,
-       BCMFMAC_USB_STATE_DOWN,
-       BCMFMAC_USB_STATE_PNP_FWDL,
-       BCMFMAC_USB_STATE_DISCONNECT,
-       BCMFMAC_USB_STATE_SLEEP
-};
-
-enum brcmf_usb_pnp_state {
-       BCMFMAC_USB_PNP_DISCONNECT,
-       BCMFMAC_USB_PNP_SLEEP,
-       BCMFMAC_USB_PNP_RESUME,
+       BRCMFMAC_USB_STATE_DOWN,
+       BRCMFMAC_USB_STATE_DL_FAIL,
+       BRCMFMAC_USB_STATE_DL_DONE,
+       BRCMFMAC_USB_STATE_UP,
+       BRCMFMAC_USB_STATE_SLEEP
 };
 
 struct brcmf_stats {
index 6d554249394fa5645376188116b61b0924942801..2044fdb555581e1f78f561913f53f2b5676f60d4 100644 (file)
 #define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
 
 #include <linux/kernel.h>
-#include <linux/if_arp.h>
-#include <linux/sched.h>
-#include <linux/kthread.h>
-#include <linux/netdevice.h>
-#include <linux/bitops.h>
 #include <linux/etherdevice.h>
-#include <linux/ieee80211.h>
-#include <linux/uaccess.h>
 #include <net/cfg80211.h>
 #include <net/netlink.h>
 
@@ -486,13 +479,6 @@ brcmf_cfg80211_change_iface(struct wiphy *wiphy, struct net_device *ndev,
 
        if (ap) {
                set_bit(BRCMF_VIF_STATUS_AP_CREATING, &ifp->vif->sme_state);
-               if (!cfg->ap_info)
-                       cfg->ap_info = kzalloc(sizeof(*cfg->ap_info),
-                                              GFP_KERNEL);
-               if (!cfg->ap_info) {
-                       err = -ENOMEM;
-                       goto done;
-               }
                WL_INFO("IF Type = AP\n");
        } else {
                err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
@@ -529,185 +515,6 @@ static void brcmf_set_mpc(struct net_device *ndev, int mpc)
        }
 }
 
-static void brcmf_iscan_prep(struct brcmf_scan_params_le *params_le,
-                            struct brcmf_ssid *ssid)
-{
-       memset(params_le->bssid, 0xFF, ETH_ALEN);
-       params_le->bss_type = DOT11_BSSTYPE_ANY;
-       params_le->scan_type = 0;
-       params_le->channel_num = 0;
-       params_le->nprobes = cpu_to_le32(-1);
-       params_le->active_time = cpu_to_le32(-1);
-       params_le->passive_time = cpu_to_le32(-1);
-       params_le->home_time = cpu_to_le32(-1);
-       if (ssid && ssid->SSID_len) {
-               params_le->ssid_le.SSID_len = cpu_to_le32(ssid->SSID_len);
-               memcpy(&params_le->ssid_le.SSID, ssid->SSID, ssid->SSID_len);
-       }
-}
-
-static s32
-brcmf_run_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan,
-               struct brcmf_ssid *ssid, u16 action)
-{
-       s32 params_size = BRCMF_SCAN_PARAMS_FIXED_SIZE +
-                         offsetof(struct brcmf_iscan_params_le, params_le);
-       struct brcmf_iscan_params_le *params;
-       s32 err = 0;
-
-       if (ssid && ssid->SSID_len)
-               params_size += sizeof(struct brcmf_ssid);
-       params = kzalloc(params_size, GFP_KERNEL);
-       if (!params)
-               return -ENOMEM;
-       BUG_ON(params_size >= BRCMF_DCMD_SMLEN);
-
-       brcmf_iscan_prep(&params->params_le, ssid);
-
-       params->version = cpu_to_le32(BRCMF_ISCAN_REQ_VERSION);
-       params->action = cpu_to_le16(action);
-       params->scan_duration = cpu_to_le16(0);
-
-       err = brcmf_fil_iovar_data_set(netdev_priv(iscan->ndev), "iscan",
-                                      params, params_size);
-       if (err) {
-               if (err == -EBUSY)
-                       WL_INFO("system busy : iscan canceled\n");
-               else
-                       WL_ERR("error (%d)\n", err);
-       }
-
-       kfree(params);
-       return err;
-}
-
-static s32 brcmf_do_iscan(struct brcmf_cfg80211_info *cfg)
-{
-       struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
-       struct net_device *ndev = cfg_to_ndev(cfg);
-       struct brcmf_ssid ssid;
-       u32 passive_scan;
-       s32 err = 0;
-
-       /* Broadcast scan by default */
-       memset(&ssid, 0, sizeof(ssid));
-
-       iscan->state = WL_ISCAN_STATE_SCANING;
-
-       passive_scan = cfg->active_scan ? 0 : 1;
-       err = brcmf_fil_cmd_int_set(netdev_priv(ndev),
-                                   BRCMF_C_SET_PASSIVE_SCAN, passive_scan);
-       if (err) {
-               WL_ERR("error (%d)\n", err);
-               return err;
-       }
-       brcmf_set_mpc(ndev, 0);
-       cfg->iscan_kickstart = true;
-       err = brcmf_run_iscan(iscan, &ssid, BRCMF_SCAN_ACTION_START);
-       if (err) {
-               brcmf_set_mpc(ndev, 1);
-               cfg->iscan_kickstart = false;
-               return err;
-       }
-       mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
-       iscan->timer_on = 1;
-       return err;
-}
-
-static s32
-brcmf_cfg80211_iscan(struct wiphy *wiphy, struct net_device *ndev,
-                    struct cfg80211_scan_request *request,
-                    struct cfg80211_ssid *this_ssid)
-{
-       struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
-       struct cfg80211_ssid *ssids;
-       struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
-       u32 passive_scan;
-       bool iscan_req;
-       bool spec_scan;
-       s32 err = 0;
-       u32 SSID_len;
-
-       if (test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
-               WL_ERR("Scanning already: status (%lu)\n", cfg->scan_status);
-               return -EAGAIN;
-       }
-       if (test_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status)) {
-               WL_ERR("Scanning being aborted: status (%lu)\n",
-                      cfg->scan_status);
-               return -EAGAIN;
-       }
-       if (test_bit(BRCMF_VIF_STATUS_CONNECTING, &ifp->vif->sme_state)) {
-               WL_ERR("Connecting: status (%lu)\n", ifp->vif->sme_state);
-               return -EAGAIN;
-       }
-
-       iscan_req = false;
-       spec_scan = false;
-       if (request) {
-               /* scan bss */
-               ssids = request->ssids;
-               if (cfg->iscan_on && (!ssids || !ssids->ssid_len))
-                       iscan_req = true;
-       } else {
-               /* scan in ibss */
-               /* we don't do iscan in ibss */
-               ssids = this_ssid;
-       }
-
-       cfg->scan_request = request;
-       set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
-       if (iscan_req) {
-               err = brcmf_do_iscan(cfg);
-               if (!err)
-                       return err;
-               else
-                       goto scan_out;
-       } else {
-               WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
-                      ssids->ssid, ssids->ssid_len);
-               memset(&sr->ssid_le, 0, sizeof(sr->ssid_le));
-               SSID_len = min_t(u8, sizeof(sr->ssid_le.SSID), ssids->ssid_len);
-               sr->ssid_le.SSID_len = cpu_to_le32(0);
-               if (SSID_len) {
-                       memcpy(sr->ssid_le.SSID, ssids->ssid, SSID_len);
-                       sr->ssid_le.SSID_len = cpu_to_le32(SSID_len);
-                       spec_scan = true;
-               } else {
-                       WL_SCAN("Broadcast scan\n");
-               }
-
-               passive_scan = cfg->active_scan ? 0 : 1;
-               err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_PASSIVE_SCAN,
-                                           passive_scan);
-               if (err) {
-                       WL_ERR("WLC_SET_PASSIVE_SCAN error (%d)\n", err);
-                       goto scan_out;
-               }
-               brcmf_set_mpc(ndev, 0);
-               err = brcmf_fil_cmd_data_set(ifp, BRCMF_C_SCAN,
-                                            &sr->ssid_le, sizeof(sr->ssid_le));
-               if (err) {
-                       if (err == -EBUSY)
-                               WL_INFO("system busy : scan for \"%s\" "
-                                       "canceled\n", sr->ssid_le.SSID);
-                       else
-                               WL_ERR("WLC_SCAN error (%d)\n", err);
-
-                       brcmf_set_mpc(ndev, 1);
-                       goto scan_out;
-               }
-       }
-
-       return 0;
-
-scan_out:
-       clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
-       cfg->scan_request = NULL;
-       return err;
-}
-
 static void brcmf_escan_prep(struct brcmf_scan_params_le *params_le,
                             struct cfg80211_scan_request *request)
 {
@@ -931,7 +738,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
        struct brcmf_if *ifp = netdev_priv(ndev);
        struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
        struct cfg80211_ssid *ssids;
-       struct brcmf_cfg80211_scan_req *sr = cfg->scan_req_int;
+       struct brcmf_cfg80211_scan_req *sr = &cfg->scan_req_int;
        u32 passive_scan;
        bool escan_req;
        bool spec_scan;
@@ -973,9 +780,7 @@ brcmf_cfg80211_escan(struct wiphy *wiphy, struct net_device *ndev,
        set_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status);
        if (escan_req) {
                err = brcmf_do_escan(cfg, wiphy, ndev, request);
-               if (!err)
-                       return err;
-               else
+               if (err)
                        goto scan_out;
        } else {
                WL_SCAN("ssid \"%s\", ssid_len (%d)\n",
@@ -1027,7 +832,6 @@ static s32
 brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
 {
        struct net_device *ndev = request->wdev->netdev;
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
        s32 err = 0;
 
        WL_TRACE("Enter\n");
@@ -1036,10 +840,7 @@ brcmf_cfg80211_scan(struct wiphy *wiphy, struct cfg80211_scan_request *request)
                                       struct brcmf_cfg80211_vif, wdev)))
                return -EIO;
 
-       if (cfg->iscan_on)
-               err = brcmf_cfg80211_iscan(wiphy, ndev, request, NULL);
-       else if (cfg->escan_on)
-               err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
+       err = brcmf_cfg80211_escan(wiphy, ndev, request, NULL);
 
        if (err)
                WL_ERR("scan error (%d)\n", err);
@@ -1075,7 +876,7 @@ static s32 brcmf_set_frag(struct net_device *ndev, u32 frag_threshold)
 static s32 brcmf_set_retry(struct net_device *ndev, u32 retry, bool l)
 {
        s32 err = 0;
-       u32 cmd = (l ? BRCM_SET_LRL : BRCM_SET_SRL);
+       u32 cmd = (l ? BRCMF_C_SET_LRL : BRCMF_C_SET_SRL);
 
        err = brcmf_fil_cmd_int_set(netdev_priv(ndev), cmd, retry);
        if (err) {
@@ -1212,8 +1013,8 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
        else
                WL_CONN("No BSSID specified\n");
 
-       if (params->channel)
-               WL_CONN("channel: %d\n", params->channel->center_freq);
+       if (params->chandef.chan)
+               WL_CONN("channel: %d\n", params->chandef.chan->center_freq);
        else
                WL_CONN("no channel specified\n");
 
@@ -1258,7 +1059,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
        else
                bcnprd = 100;
 
-       err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_BCNPRD, bcnprd);
+       err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_BCNPRD, bcnprd);
        if (err) {
                WL_ERR("WLC_SET_BCNPRD failed (%d)\n", err);
                goto done;
@@ -1286,12 +1087,12 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
        }
 
        /* Channel */
-       if (params->channel) {
+       if (params->chandef.chan) {
                u32 target_channel;
 
                cfg->channel =
                        ieee80211_frequency_to_channel(
-                               params->channel->center_freq);
+                               params->chandef.chan->center_freq);
                if (params->channel_fixed) {
                        /* adding chanspec */
                        brcmf_ch_to_chanspec(cfg->channel,
@@ -1300,7 +1101,7 @@ brcmf_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *ndev,
 
                /* set channel for starter */
                target_channel = cfg->channel;
-               err = brcmf_fil_cmd_int_set(ifp, BRCM_SET_CHANNEL,
+               err = brcmf_fil_cmd_int_set(ifp, BRCMF_C_SET_CHANNEL,
                                            target_channel);
                if (err) {
                        WL_ERR("WLC_SET_CHANNEL failed (%d)\n", err);
@@ -1721,7 +1522,7 @@ brcmf_cfg80211_disconnect(struct wiphy *wiphy, struct net_device *ndev,
 }
 
 static s32
-brcmf_cfg80211_set_tx_power(struct wiphy *wiphy,
+brcmf_cfg80211_set_tx_power(struct wiphy *wiphy, struct wireless_dev *wdev,
                            enum nl80211_tx_power_setting type, s32 mbm)
 {
 
@@ -1770,7 +1571,9 @@ done:
        return err;
 }
 
-static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy, s32 *dbm)
+static s32 brcmf_cfg80211_get_tx_power(struct wiphy *wiphy,
+                                      struct wireless_dev *wdev,
+                                      s32 *dbm)
 {
        struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
@@ -2014,6 +1817,12 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
        if (!check_vif_up(ifp->vif))
                return -EIO;
 
+       if (key_idx >= DOT11_MAX_DEFAULT_KEYS) {
+               /* we ignore this key index in this case */
+               WL_ERR("invalid key index (%d)\n", key_idx);
+               return -EINVAL;
+       }
+
        memset(&key, 0, sizeof(key));
 
        key.index = (u32) key_idx;
@@ -2024,15 +1833,6 @@ brcmf_cfg80211_del_key(struct wiphy *wiphy, struct net_device *ndev,
 
        /* Set the new key/index */
        err = send_key_to_dongle(ndev, &key);
-       if (err) {
-               if (err == -EINVAL) {
-                       if (key.index >= DOT11_MAX_DEFAULT_KEYS)
-                               /* we ignore this key index in this case */
-                               WL_ERR("invalid key index (%d)\n", key_idx);
-               }
-               /* Ignore this error, may happen during DISASSOC */
-               err = -EAGAIN;
-       }
 
        WL_TRACE("Exit\n");
        return err;
@@ -2239,7 +2039,7 @@ brcmf_cfg80211_set_bitrate_mask(struct wiphy *wiphy, struct net_device *ndev,
 
        /* addr param is always NULL. ignore it */
        /* Get current rateset */
-       err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_CURR_RATESET,
+       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CURR_RATESET,
                                     &rateset_le, sizeof(rateset_le));
        if (err) {
                WL_ERR("could not get current rateset (%d)\n", err);
@@ -2354,13 +2154,14 @@ static s32 brcmf_inform_bss(struct brcmf_cfg80211_info *cfg)
        int i;
 
        bss_list = cfg->bss_list;
-       if (bss_list->version != BRCMF_BSS_INFO_VERSION) {
+       if (bss_list->count != 0 &&
+           bss_list->version != BRCMF_BSS_INFO_VERSION) {
                WL_ERR("Version %d != WL_BSS_INFO_VERSION\n",
                       bss_list->version);
                return -EOPNOTSUPP;
        }
        WL_SCAN("scanned AP count (%d)\n", bss_list->count);
-       for (i = 0; i < bss_list->count && i < WL_AP_MAX; i++) {
+       for (i = 0; i < bss_list->count; i++) {
                bi = next_bss_le(bss_list, bi);
                err = brcmf_inform_single_bss(cfg, bi);
                if (err)
@@ -2582,33 +2383,10 @@ update_bss_info_out:
 
 static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
 {
-       struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
        struct escan_info *escan = &cfg->escan_info;
-       struct brcmf_ssid ssid;
 
        set_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
-       if (cfg->iscan_on) {
-               iscan->state = WL_ISCAN_STATE_IDLE;
-
-               if (iscan->timer_on) {
-                       del_timer_sync(&iscan->timer);
-                       iscan->timer_on = 0;
-               }
-
-               cancel_work_sync(&iscan->work);
-
-               /* Abort iscan running in FW */
-               memset(&ssid, 0, sizeof(ssid));
-               brcmf_run_iscan(iscan, &ssid, WL_SCAN_ACTION_ABORT);
-
-               if (cfg->scan_request) {
-                       /* Indidate scan abort to cfg80211 layer */
-                       WL_INFO("Terminating scan in progress\n");
-                       cfg80211_scan_done(cfg->scan_request, true);
-                       cfg->scan_request = NULL;
-               }
-       }
-       if (cfg->escan_on && cfg->scan_request) {
+       if (cfg->scan_request) {
                escan->escan_state = WL_ESCAN_STATE_IDLE;
                brcmf_notify_escan_complete(cfg, escan->ndev, true, true);
        }
@@ -2616,198 +2394,6 @@ static void brcmf_abort_scanning(struct brcmf_cfg80211_info *cfg)
        clear_bit(BRCMF_SCAN_STATUS_ABORT, &cfg->scan_status);
 }
 
-static void brcmf_notify_iscan_complete(struct brcmf_cfg80211_iscan_ctrl *iscan,
-                                       bool aborted)
-{
-       struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan);
-       struct net_device *ndev = cfg_to_ndev(cfg);
-
-       if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
-               WL_ERR("Scan complete while device not scanning\n");
-               return;
-       }
-       if (cfg->scan_request) {
-               WL_SCAN("ISCAN Completed scan: %s\n",
-                               aborted ? "Aborted" : "Done");
-               cfg80211_scan_done(cfg->scan_request, aborted);
-               brcmf_set_mpc(ndev, 1);
-               cfg->scan_request = NULL;
-       }
-       cfg->iscan_kickstart = false;
-}
-
-static s32 brcmf_wakeup_iscan(struct brcmf_cfg80211_iscan_ctrl *iscan)
-{
-       if (iscan->state != WL_ISCAN_STATE_IDLE) {
-               WL_SCAN("wake up iscan\n");
-               schedule_work(&iscan->work);
-               return 0;
-       }
-
-       return -EIO;
-}
-
-static s32
-brcmf_get_iscan_results(struct brcmf_cfg80211_iscan_ctrl *iscan, u32 *status,
-                    struct brcmf_scan_results **bss_list)
-{
-       struct brcmf_scan_results *results;
-       struct brcmf_scan_results_le *results_le;
-       struct brcmf_iscan_results *list_buf;
-       s32 err = 0;
-
-       memset(iscan->scan_buf, 0, WL_ISCAN_BUF_MAX);
-       list_buf = (struct brcmf_iscan_results *)iscan->scan_buf;
-       results = &list_buf->results;
-       results_le = &list_buf->results_le;
-       results_le->buflen = cpu_to_le32(sizeof(iscan->scan_buf));
-       results_le->version = 0;
-       results_le->count = 0;
-
-       err = brcmf_fil_iovar_data_get(netdev_priv(iscan->ndev), "iscanresults",
-                                      iscan->scan_buf,
-                                      sizeof(iscan->scan_buf));
-       if (err) {
-               WL_ERR("error (%d)\n", err);
-               return err;
-       }
-       results->buflen = le32_to_cpu(results_le->buflen);
-       results->version = le32_to_cpu(results_le->version);
-       results->count = le32_to_cpu(results_le->count);
-       WL_SCAN("results->count = %d\n", results_le->count);
-       WL_SCAN("results->buflen = %d\n", results_le->buflen);
-       *status = le32_to_cpu(list_buf->status_le);
-       WL_SCAN("status = %d\n", *status);
-       *bss_list = results;
-
-       return err;
-}
-
-static s32 brcmf_iscan_done(struct brcmf_cfg80211_info *cfg)
-{
-       struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
-       s32 err = 0;
-
-       iscan->state = WL_ISCAN_STATE_IDLE;
-       brcmf_inform_bss(cfg);
-       brcmf_notify_iscan_complete(iscan, false);
-
-       return err;
-}
-
-static s32 brcmf_iscan_pending(struct brcmf_cfg80211_info *cfg)
-{
-       struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
-       s32 err = 0;
-
-       /* Reschedule the timer */
-       mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
-       iscan->timer_on = 1;
-
-       return err;
-}
-
-static s32 brcmf_iscan_inprogress(struct brcmf_cfg80211_info *cfg)
-{
-       struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
-       s32 err = 0;
-
-       brcmf_inform_bss(cfg);
-       brcmf_run_iscan(iscan, NULL, BRCMF_SCAN_ACTION_CONTINUE);
-       /* Reschedule the timer */
-       mod_timer(&iscan->timer, jiffies + iscan->timer_ms * HZ / 1000);
-       iscan->timer_on = 1;
-
-       return err;
-}
-
-static s32 brcmf_iscan_aborted(struct brcmf_cfg80211_info *cfg)
-{
-       struct brcmf_cfg80211_iscan_ctrl *iscan = cfg->iscan;
-       s32 err = 0;
-
-       iscan->state = WL_ISCAN_STATE_IDLE;
-       brcmf_notify_iscan_complete(iscan, true);
-
-       return err;
-}
-
-static void brcmf_cfg80211_iscan_handler(struct work_struct *work)
-{
-       struct brcmf_cfg80211_iscan_ctrl *iscan =
-                       container_of(work, struct brcmf_cfg80211_iscan_ctrl,
-                                    work);
-       struct brcmf_cfg80211_info *cfg = iscan_to_cfg(iscan);
-       struct brcmf_cfg80211_iscan_eloop *el = &iscan->el;
-       u32 status = BRCMF_SCAN_RESULTS_PARTIAL;
-
-       if (iscan->timer_on) {
-               del_timer_sync(&iscan->timer);
-               iscan->timer_on = 0;
-       }
-
-       if (brcmf_get_iscan_results(iscan, &status, &cfg->bss_list)) {
-               status = BRCMF_SCAN_RESULTS_ABORTED;
-               WL_ERR("Abort iscan\n");
-       }
-
-       el->handler[status](cfg);
-}
-
-static void brcmf_iscan_timer(unsigned long data)
-{
-       struct brcmf_cfg80211_iscan_ctrl *iscan =
-                       (struct brcmf_cfg80211_iscan_ctrl *)data;
-
-       if (iscan) {
-               iscan->timer_on = 0;
-               WL_SCAN("timer expired\n");
-               brcmf_wakeup_iscan(iscan);
-       }
-}
-
-static s32 brcmf_invoke_iscan(struct brcmf_cfg80211_info *cfg)
-{
-       struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
-
-       if (cfg->iscan_on) {
-               iscan->state = WL_ISCAN_STATE_IDLE;
-               INIT_WORK(&iscan->work, brcmf_cfg80211_iscan_handler);
-       }
-
-       return 0;
-}
-
-static void brcmf_init_iscan_eloop(struct brcmf_cfg80211_iscan_eloop *el)
-{
-       memset(el, 0, sizeof(*el));
-       el->handler[BRCMF_SCAN_RESULTS_SUCCESS] = brcmf_iscan_done;
-       el->handler[BRCMF_SCAN_RESULTS_PARTIAL] = brcmf_iscan_inprogress;
-       el->handler[BRCMF_SCAN_RESULTS_PENDING] = brcmf_iscan_pending;
-       el->handler[BRCMF_SCAN_RESULTS_ABORTED] = brcmf_iscan_aborted;
-       el->handler[BRCMF_SCAN_RESULTS_NO_MEM] = brcmf_iscan_aborted;
-}
-
-static s32 brcmf_init_iscan(struct brcmf_cfg80211_info *cfg)
-{
-       struct brcmf_cfg80211_iscan_ctrl *iscan = cfg_to_iscan(cfg);
-       int err = 0;
-
-       if (cfg->iscan_on) {
-               iscan->ndev = cfg_to_ndev(cfg);
-               brcmf_init_iscan_eloop(&iscan->el);
-               iscan->timer_ms = WL_ISCAN_TIMER_INTERVAL_MS;
-               init_timer(&iscan->timer);
-               iscan->timer.data = (unsigned long) iscan;
-               iscan->timer.function = brcmf_iscan_timer;
-               err = brcmf_invoke_iscan(cfg);
-               if (!err)
-                       iscan->data = cfg;
-       }
-
-       return err;
-}
-
 static void brcmf_cfg80211_escan_timeout_worker(struct work_struct *work)
 {
        struct brcmf_cfg80211_info *cfg =
@@ -2825,8 +2411,7 @@ static void brcmf_escan_timeout(unsigned long data)
 
        if (cfg->scan_request) {
                WL_ERR("timer expired\n");
-               if (cfg->escan_on)
-                       schedule_work(&cfg->escan_timeout_work);
+               schedule_work(&cfg->escan_timeout_work);
        }
 }
 
@@ -2863,10 +2448,11 @@ brcmf_compare_update_same_bss(struct brcmf_bss_info_le *bss,
 }
 
 static s32
-brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg,
-                            struct net_device *ndev,
+brcmf_cfg80211_escan_handler(struct brcmf_if *ifp,
                             const struct brcmf_event_msg *e, void *data)
 {
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+       struct net_device *ndev = ifp->ndev;
        s32 status;
        s32 err = 0;
        struct brcmf_escan_result_le *escan_result_le;
@@ -2877,13 +2463,11 @@ brcmf_cfg80211_escan_handler(struct brcmf_cfg80211_info *cfg,
        u32 i;
        bool aborted;
 
-       status = be32_to_cpu(e->status);
+       status = e->status;
 
-       if (!ndev || !cfg->escan_on ||
-                       !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
-               WL_ERR("scan not ready ndev %p wl->escan_on %d drv_status %x\n",
-                       ndev, cfg->escan_on,
-                       !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
+       if (!ndev || !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
+               WL_ERR("scan not ready ndev %p drv_status %x\n", ndev,
+                      !test_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status));
                return -EPERM;
        }
 
@@ -2960,18 +2544,15 @@ exit:
 
 static void brcmf_init_escan(struct brcmf_cfg80211_info *cfg)
 {
-
-       if (cfg->escan_on) {
-               cfg->el.handler[BRCMF_E_ESCAN_RESULT] =
-                       brcmf_cfg80211_escan_handler;
-               cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
-               /* Init scan_timeout timer */
-               init_timer(&cfg->escan_timeout);
-               cfg->escan_timeout.data = (unsigned long) cfg;
-               cfg->escan_timeout.function = brcmf_escan_timeout;
-               INIT_WORK(&cfg->escan_timeout_work,
-                       brcmf_cfg80211_escan_timeout_worker);
-       }
+       brcmf_fweh_register(cfg->pub, BRCMF_E_ESCAN_RESULT,
+                           brcmf_cfg80211_escan_handler);
+       cfg->escan_info.escan_state = WL_ESCAN_STATE_IDLE;
+       /* Init scan_timeout timer */
+       init_timer(&cfg->escan_timeout);
+       cfg->escan_timeout.data = (unsigned long) cfg;
+       cfg->escan_timeout.function = brcmf_escan_timeout;
+       INIT_WORK(&cfg->escan_timeout_work,
+                 brcmf_cfg80211_escan_timeout_worker);
 }
 
 static __always_inline void brcmf_delay(u32 ms)
@@ -2986,20 +2567,8 @@ static __always_inline void brcmf_delay(u32 ms)
 
 static s32 brcmf_cfg80211_resume(struct wiphy *wiphy)
 {
-       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
-       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
-
-       /*
-        * Check for BRCMF_VIF_STATUS_READY before any function call which
-        * could result is bus access. Don't block the resume for
-        * any driver error conditions
-        */
        WL_TRACE("Enter\n");
 
-       if (check_vif_up(ifp->vif))
-               brcmf_invoke_iscan(cfg);
-
-       WL_TRACE("Exit\n");
        return 0;
 }
 
@@ -3198,10 +2767,11 @@ brcmf_cfg80211_flush_pmksa(struct wiphy *wiphy, struct net_device *ndev)
  * cfg80211_scan_request one out of the received PNO event.
  */
 static s32
-brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg,
-                               struct net_device *ndev,
+brcmf_notify_sched_scan_results(struct brcmf_if *ifp,
                                const struct brcmf_event_msg *e, void *data)
 {
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+       struct net_device *ndev = ifp->ndev;
        struct brcmf_pno_net_info_le *netinfo, *netinfo_start;
        struct cfg80211_scan_request *request = NULL;
        struct cfg80211_ssid *ssid = NULL;
@@ -3216,7 +2786,7 @@ brcmf_notify_sched_scan_results(struct brcmf_cfg80211_info *cfg,
 
        WL_SCAN("Enter\n");
 
-       if (e->event_type == cpu_to_be32(BRCMF_E_PFN_NET_LOST)) {
+       if (e->event_code == BRCMF_E_PFN_NET_LOST) {
                WL_SCAN("PFN NET LOST event. Do Nothing\n");
                return 0;
        }
@@ -3309,7 +2879,6 @@ out_err:
        return err;
 }
 
-#ifndef CONFIG_BRCMISCAN
 static int brcmf_dev_pno_clean(struct net_device *ndev)
 {
        int ret;
@@ -3446,7 +3015,6 @@ static int brcmf_cfg80211_sched_scan_stop(struct wiphy *wiphy,
                brcmf_notify_escan_complete(cfg, ndev, true, true);
        return 0;
 }
-#endif /* CONFIG_BRCMISCAN */
 
 #ifdef CONFIG_NL80211_TESTMODE
 static int brcmf_cfg80211_testmode(struct wiphy *wiphy, void *data, int len)
@@ -3512,7 +3080,7 @@ static bool brcmf_valid_wpa_oui(u8 *oui, bool is_rsn_ie)
 
 static s32
 brcmf_configure_wpaie(struct net_device *ndev, struct brcmf_vs_tlv *wpa_ie,
-                    bool is_rsn_ie, s32 bssidx)
+                    bool is_rsn_ie)
 {
        struct brcmf_if *ifp = netdev_priv(ndev);
        u32 auth = 0; /* d11 open authentication */
@@ -3689,7 +3257,7 @@ exit:
 }
 
 static s32
-brcmf_parse_vndr_ies(u8 *vndr_ie_buf, u32 vndr_ie_len,
+brcmf_parse_vndr_ies(const u8 *vndr_ie_buf, u32 vndr_ie_len,
                     struct parsed_vndr_ies *vndr_ies)
 {
        s32 err = 0;
@@ -3768,13 +3336,12 @@ brcmf_vndr_ie(u8 *iebuf, s32 pktflag, u8 *ie_ptr, u32 ie_len, s8 *add_del_cmd)
        return ie_len + VNDR_IE_HDR_SIZE;
 }
 
-static s32
-brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
-                       struct net_device *ndev, s32 pktflag,
-                       u8 *vndr_ie_buf, u32 vndr_ie_len)
+static
+s32 brcmf_vif_set_mgmt_ie(struct brcmf_cfg80211_vif *vif, s32 pktflag,
+                         const u8 *vndr_ie_buf, u32 vndr_ie_len)
 {
-       struct brcmf_if *ifp = netdev_priv(ndev);
-       struct vif_saved_ie *saved_ie = &ifp->vif->saved_ie;
+       struct brcmf_if *ifp;
+       struct vif_saved_ie *saved_ie;
        s32 err = 0;
        u8  *iovar_ie_buf;
        u8  *curr_ie_buf;
@@ -3791,8 +3358,12 @@ brcmf_set_management_ie(struct brcmf_cfg80211_info *cfg,
        u8 *ptr;
        int remained_buf_len;
 
-       WL_TRACE("bssidx %d, pktflag : 0x%02X\n",
-                brcmf_ndev_bssidx(ndev), pktflag);
+       if (!vif)
+               return -ENODEV;
+       ifp = vif->ifp;
+       saved_ie = &vif->saved_ie;
+
+       WL_TRACE("bssidx %d, pktflag : 0x%02X\n", ifp->bssidx, pktflag);
        iovar_ie_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
        if (!iovar_ie_buf)
                return -ENOMEM;
@@ -3932,13 +3503,13 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        struct brcmf_tlv *rsn_ie;
        struct brcmf_vs_tlv *wpa_ie;
        struct brcmf_join_params join_params;
-       struct brcmf_cfg80211_info *cfg = wiphy_to_cfg(wiphy);
        s32 bssidx = 0;
 
        WL_TRACE("channel_type=%d, beacon_interval=%d, dtim_period=%d,\n",
-                settings->channel_type, settings->beacon_interval,
+                cfg80211_get_chandef_type(&settings->chandef),
+                settings->beacon_interval,
                 settings->dtim_period);
-       WL_TRACE("ssid=%s(%d), auth_type=%d, inactivity_timeout=%d\n",
+       WL_TRACE("ssid=%s(%zu), auth_type=%d, inactivity_timeout=%d\n",
                 settings->ssid, settings->ssid_len, settings->auth_type,
                 settings->inactivity_timeout);
 
@@ -3990,55 +3561,39 @@ brcmf_cfg80211_start_ap(struct wiphy *wiphy, struct net_device *ndev,
        wpa_ie = brcmf_find_wpaie((u8 *)settings->beacon.tail,
                                  settings->beacon.tail_len);
 
-       kfree(cfg->ap_info->rsn_ie);
-       cfg->ap_info->rsn_ie = NULL;
-       kfree(cfg->ap_info->wpa_ie);
-       cfg->ap_info->wpa_ie = NULL;
-
        if ((wpa_ie != NULL || rsn_ie != NULL)) {
                WL_TRACE("WPA(2) IE is found\n");
                if (wpa_ie != NULL) {
                        /* WPA IE */
-                       err = brcmf_configure_wpaie(ndev, wpa_ie, false,
-                                                   bssidx);
+                       err = brcmf_configure_wpaie(ndev, wpa_ie, false);
                        if (err < 0)
                                goto exit;
-                       cfg->ap_info->wpa_ie = kmemdup(wpa_ie,
-                                                           wpa_ie->len +
-                                                           TLV_HDR_LEN,
-                                                           GFP_KERNEL);
                } else {
                        /* RSN IE */
                        err = brcmf_configure_wpaie(ndev,
-                               (struct brcmf_vs_tlv *)rsn_ie, true, bssidx);
+                               (struct brcmf_vs_tlv *)rsn_ie, true);
                        if (err < 0)
                                goto exit;
-                       cfg->ap_info->rsn_ie = kmemdup(rsn_ie,
-                                                           rsn_ie->len +
-                                                           TLV_HDR_LEN,
-                                                           GFP_KERNEL);
                }
-               cfg->ap_info->security_mode = true;
        } else {
                WL_TRACE("No WPA(2) IEs found\n");
                brcmf_configure_opensecurity(ndev, bssidx);
-               cfg->ap_info->security_mode = false;
        }
        /* Set Beacon IEs to FW */
-       err = brcmf_set_management_ie(cfg, ndev,
-                                     VNDR_IE_BEACON_FLAG,
-                                     (u8 *)settings->beacon.tail,
-                                     settings->beacon.tail_len);
+       err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
+                                   VNDR_IE_BEACON_FLAG,
+                                   settings->beacon.tail,
+                                   settings->beacon.tail_len);
        if (err)
                WL_ERR("Set Beacon IE Failed\n");
        else
                WL_TRACE("Applied Vndr IEs for Beacon\n");
 
        /* Set Probe Response IEs to FW */
-       err = brcmf_set_management_ie(cfg, ndev,
-                                     VNDR_IE_PRBRSP_FLAG,
-                                     (u8 *)settings->beacon.proberesp_ies,
-                                     settings->beacon.proberesp_ies_len);
+       err = brcmf_vif_set_mgmt_ie(ndev_to_vif(ndev),
+                                   VNDR_IE_PRBRSP_FLAG,
+                                   settings->beacon.proberesp_ies,
+                                   settings->beacon.proberesp_ies_len);
        if (err)
                WL_ERR("Set Probe Resp IE Failed\n");
        else
@@ -4169,11 +3724,8 @@ static struct cfg80211_ops wl_cfg80211_ops = {
        .start_ap = brcmf_cfg80211_start_ap,
        .stop_ap = brcmf_cfg80211_stop_ap,
        .del_station = brcmf_cfg80211_del_station,
-#ifndef CONFIG_BRCMISCAN
-       /* scheduled scan need e-scan, which is mutual exclusive with i-scan */
        .sched_scan_start = brcmf_cfg80211_sched_scan_start,
        .sched_scan_stop = brcmf_cfg80211_sched_scan_stop,
-#endif
 #ifdef CONFIG_NL80211_TESTMODE
        .testmode_cmd = brcmf_cfg80211_testmode
 #endif
@@ -4197,13 +3749,11 @@ static s32 brcmf_mode_to_nl80211_iftype(s32 mode)
 
 static void brcmf_wiphy_pno_params(struct wiphy *wiphy)
 {
-#ifndef CONFIG_BRCMISCAN
        /* scheduled scan settings */
        wiphy->max_sched_scan_ssids = BRCMF_PNO_MAX_PFN_COUNT;
        wiphy->max_match_sets = BRCMF_PNO_MAX_PFN_COUNT;
        wiphy->max_sched_scan_ie_len = BRCMF_SCAN_IE_LEN_MAX;
        wiphy->flags |= WIPHY_FLAG_SUPPORTS_SCHED_SCAN;
-#endif
 }
 
 static struct wiphy *brcmf_setup_wiphy(struct device *phydev)
@@ -4302,8 +3852,8 @@ static void brcmf_free_vif(struct brcmf_cfg80211_vif *vif)
 static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
                            const struct brcmf_event_msg *e)
 {
-       u32 event = be32_to_cpu(e->event_type);
-       u32 status = be32_to_cpu(e->status);
+       u32 event = e->event_code;
+       u32 status = e->status;
 
        if (event == BRCMF_E_SET_SSID && status == BRCMF_E_STATUS_SUCCESS) {
                WL_CONN("Processing set ssid\n");
@@ -4317,8 +3867,8 @@ static bool brcmf_is_linkup(struct brcmf_cfg80211_info *cfg,
 static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg,
                              const struct brcmf_event_msg *e)
 {
-       u32 event = be32_to_cpu(e->event_type);
-       u16 flags = be16_to_cpu(e->flags);
+       u32 event = e->event_code;
+       u16 flags = e->flags;
 
        if (event == BRCMF_E_LINK && (!(flags & BRCMF_EVENT_MSG_LINK))) {
                WL_CONN("Processing link down\n");
@@ -4330,13 +3880,12 @@ static bool brcmf_is_linkdown(struct brcmf_cfg80211_info *cfg,
 static bool brcmf_is_nonetwork(struct brcmf_cfg80211_info *cfg,
                               const struct brcmf_event_msg *e)
 {
-       u32 event = be32_to_cpu(e->event_type);
-       u32 status = be32_to_cpu(e->status);
+       u32 event = e->event_code;
+       u32 status = e->status;
 
        if (event == BRCMF_E_LINK && status == BRCMF_E_STATUS_NO_NETWORKS) {
                WL_CONN("Processing Link %s & no network found\n",
-                               be16_to_cpu(e->flags) & BRCMF_EVENT_MSG_LINK ?
-                               "up" : "down");
+                       e->flags & BRCMF_EVENT_MSG_LINK ? "up" : "down");
                return true;
        }
 
@@ -4524,9 +4073,9 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
                               const struct brcmf_event_msg *e, void *data)
 {
        s32 err = 0;
-       u32 event = be32_to_cpu(e->event_type);
-       u32 reason = be32_to_cpu(e->reason);
-       u32 len = be32_to_cpu(e->datalen);
+       u32 event = e->event_code;
+       u32 reason = e->reason;
+       u32 len = e->datalen;
        static int generation;
 
        struct station_info sinfo;
@@ -4558,11 +4107,11 @@ brcmf_notify_connect_status_ap(struct brcmf_cfg80211_info *cfg,
 }
 
 static s32
-brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg,
-                           struct net_device *ndev,
+brcmf_notify_connect_status(struct brcmf_if *ifp,
                            const struct brcmf_event_msg *e, void *data)
 {
-       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
+       struct net_device *ndev = ifp->ndev;
        struct brcmf_cfg80211_profile *profile = &ifp->vif->profile;
        s32 err = 0;
 
@@ -4610,31 +4159,29 @@ brcmf_notify_connect_status(struct brcmf_cfg80211_info *cfg,
 }
 
 static s32
-brcmf_notify_roaming_status(struct brcmf_cfg80211_info *cfg,
-                           struct net_device *ndev,
+brcmf_notify_roaming_status(struct brcmf_if *ifp,
                            const struct brcmf_event_msg *e, void *data)
 {
-       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        s32 err = 0;
-       u32 event = be32_to_cpu(e->event_type);
-       u32 status = be32_to_cpu(e->status);
+       u32 event = e->event_code;
+       u32 status = e->status;
 
        if (event == BRCMF_E_ROAM && status == BRCMF_E_STATUS_SUCCESS) {
                if (test_bit(BRCMF_VIF_STATUS_CONNECTED, &ifp->vif->sme_state))
-                       brcmf_bss_roaming_done(cfg, ndev, e);
+                       brcmf_bss_roaming_done(cfg, ifp->ndev, e);
                else
-                       brcmf_bss_connect_done(cfg, ndev, e, true);
+                       brcmf_bss_connect_done(cfg, ifp->ndev, e, true);
        }
 
        return err;
 }
 
 static s32
-brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg,
-                       struct net_device *ndev,
+brcmf_notify_mic_status(struct brcmf_if *ifp,
                        const struct brcmf_event_msg *e, void *data)
 {
-       u16 flags = be16_to_cpu(e->flags);
+       u16 flags = e->flags;
        enum nl80211_key_type key_type;
 
        if (flags & BRCMF_EVENT_MSG_GROUP)
@@ -4642,84 +4189,12 @@ brcmf_notify_mic_status(struct brcmf_cfg80211_info *cfg,
        else
                key_type = NL80211_KEYTYPE_PAIRWISE;
 
-       cfg80211_michael_mic_failure(ndev, (u8 *)&e->addr, key_type, -1,
+       cfg80211_michael_mic_failure(ifp->ndev, (u8 *)&e->addr, key_type, -1,
                                     NULL, GFP_KERNEL);
 
        return 0;
 }
 
-static s32
-brcmf_notify_scan_status(struct brcmf_cfg80211_info *cfg,
-                        struct net_device *ndev,
-                        const struct brcmf_event_msg *e, void *data)
-{
-       struct brcmf_if *ifp = netdev_priv(ndev);
-       struct brcmf_channel_info_le channel_inform_le;
-       struct brcmf_scan_results_le *bss_list_le;
-       u32 len = WL_SCAN_BUF_MAX;
-       s32 err = 0;
-       bool scan_abort = false;
-       u32 scan_channel;
-
-       WL_TRACE("Enter\n");
-
-       if (cfg->iscan_on && cfg->iscan_kickstart) {
-               WL_TRACE("Exit\n");
-               return brcmf_wakeup_iscan(cfg_to_iscan(cfg));
-       }
-
-       if (!test_and_clear_bit(BRCMF_SCAN_STATUS_BUSY, &cfg->scan_status)) {
-               WL_ERR("Scan complete while device not scanning\n");
-               scan_abort = true;
-               err = -EINVAL;
-               goto scan_done_out;
-       }
-
-       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_CHANNEL,
-                                    &channel_inform_le,
-                                    sizeof(channel_inform_le));
-       if (err) {
-               WL_ERR("scan busy (%d)\n", err);
-               scan_abort = true;
-               goto scan_done_out;
-       }
-       scan_channel = le32_to_cpu(channel_inform_le.scan_channel);
-       if (scan_channel)
-               WL_CONN("channel_inform.scan_channel (%d)\n", scan_channel);
-       cfg->bss_list = cfg->scan_results;
-       bss_list_le = (struct brcmf_scan_results_le *) cfg->bss_list;
-
-       memset(cfg->scan_results, 0, len);
-       bss_list_le->buflen = cpu_to_le32(len);
-       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_SCAN_RESULTS,
-                                    cfg->scan_results, len);
-       if (err) {
-               WL_ERR("%s Scan_results error (%d)\n", ndev->name, err);
-               err = -EINVAL;
-               scan_abort = true;
-               goto scan_done_out;
-       }
-       cfg->scan_results->buflen = le32_to_cpu(bss_list_le->buflen);
-       cfg->scan_results->version = le32_to_cpu(bss_list_le->version);
-       cfg->scan_results->count = le32_to_cpu(bss_list_le->count);
-
-       err = brcmf_inform_bss(cfg);
-       if (err)
-               scan_abort = true;
-
-scan_done_out:
-       if (cfg->scan_request) {
-               WL_SCAN("calling cfg80211_scan_done\n");
-               cfg80211_scan_done(cfg->scan_request, scan_abort);
-               brcmf_set_mpc(ndev, 1);
-               cfg->scan_request = NULL;
-       }
-
-       WL_TRACE("Exit\n");
-
-       return err;
-}
-
 static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
 {
        conf->mode = (u32)-1;
@@ -4730,77 +4205,53 @@ static void brcmf_init_conf(struct brcmf_cfg80211_conf *conf)
        conf->tx_power = -1;
 }
 
-static void brcmf_init_eloop_handler(struct brcmf_cfg80211_event_loop *el)
-{
-       memset(el, 0, sizeof(*el));
-       el->handler[BRCMF_E_SCAN_COMPLETE] = brcmf_notify_scan_status;
-       el->handler[BRCMF_E_LINK] = brcmf_notify_connect_status;
-       el->handler[BRCMF_E_DEAUTH_IND] = brcmf_notify_connect_status;
-       el->handler[BRCMF_E_DEAUTH] = brcmf_notify_connect_status;
-       el->handler[BRCMF_E_DISASSOC_IND] = brcmf_notify_connect_status;
-       el->handler[BRCMF_E_ASSOC_IND] = brcmf_notify_connect_status;
-       el->handler[BRCMF_E_REASSOC_IND] = brcmf_notify_connect_status;
-       el->handler[BRCMF_E_ROAM] = brcmf_notify_roaming_status;
-       el->handler[BRCMF_E_MIC_ERROR] = brcmf_notify_mic_status;
-       el->handler[BRCMF_E_SET_SSID] = brcmf_notify_connect_status;
-       el->handler[BRCMF_E_PFN_NET_FOUND] = brcmf_notify_sched_scan_results;
+static void brcmf_register_event_handlers(struct brcmf_cfg80211_info *cfg)
+{
+       brcmf_fweh_register(cfg->pub, BRCMF_E_LINK,
+                           brcmf_notify_connect_status);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH_IND,
+                           brcmf_notify_connect_status);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_DEAUTH,
+                           brcmf_notify_connect_status);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_DISASSOC_IND,
+                           brcmf_notify_connect_status);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_ASSOC_IND,
+                           brcmf_notify_connect_status);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_REASSOC_IND,
+                           brcmf_notify_connect_status);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_ROAM,
+                           brcmf_notify_roaming_status);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_MIC_ERROR,
+                           brcmf_notify_mic_status);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_SET_SSID,
+                           brcmf_notify_connect_status);
+       brcmf_fweh_register(cfg->pub, BRCMF_E_PFN_NET_FOUND,
+                           brcmf_notify_sched_scan_results);
 }
 
 static void brcmf_deinit_priv_mem(struct brcmf_cfg80211_info *cfg)
 {
-       kfree(cfg->scan_results);
-       cfg->scan_results = NULL;
-       kfree(cfg->bss_info);
-       cfg->bss_info = NULL;
        kfree(cfg->conf);
        cfg->conf = NULL;
-       kfree(cfg->scan_req_int);
-       cfg->scan_req_int = NULL;
        kfree(cfg->escan_ioctl_buf);
        cfg->escan_ioctl_buf = NULL;
-       kfree(cfg->dcmd_buf);
-       cfg->dcmd_buf = NULL;
        kfree(cfg->extra_buf);
        cfg->extra_buf = NULL;
-       kfree(cfg->iscan);
-       cfg->iscan = NULL;
        kfree(cfg->pmk_list);
        cfg->pmk_list = NULL;
-       if (cfg->ap_info) {
-               kfree(cfg->ap_info->wpa_ie);
-               kfree(cfg->ap_info->rsn_ie);
-               kfree(cfg->ap_info);
-               cfg->ap_info = NULL;
-       }
 }
 
 static s32 brcmf_init_priv_mem(struct brcmf_cfg80211_info *cfg)
 {
-       cfg->scan_results = kzalloc(WL_SCAN_BUF_MAX, GFP_KERNEL);
-       if (!cfg->scan_results)
-               goto init_priv_mem_out;
        cfg->conf = kzalloc(sizeof(*cfg->conf), GFP_KERNEL);
        if (!cfg->conf)
                goto init_priv_mem_out;
-       cfg->bss_info = kzalloc(WL_BSS_INFO_MAX, GFP_KERNEL);
-       if (!cfg->bss_info)
-               goto init_priv_mem_out;
-       cfg->scan_req_int = kzalloc(sizeof(*cfg->scan_req_int),
-                                        GFP_KERNEL);
-       if (!cfg->scan_req_int)
-               goto init_priv_mem_out;
        cfg->escan_ioctl_buf = kzalloc(BRCMF_DCMD_MEDLEN, GFP_KERNEL);
        if (!cfg->escan_ioctl_buf)
                goto init_priv_mem_out;
-       cfg->dcmd_buf = kzalloc(WL_DCMD_LEN_MAX, GFP_KERNEL);
-       if (!cfg->dcmd_buf)
-               goto init_priv_mem_out;
        cfg->extra_buf = kzalloc(WL_EXTRA_BUF_MAX, GFP_KERNEL);
        if (!cfg->extra_buf)
                goto init_priv_mem_out;
-       cfg->iscan = kzalloc(sizeof(*cfg->iscan), GFP_KERNEL);
-       if (!cfg->iscan)
-               goto init_priv_mem_out;
        cfg->pmk_list = kzalloc(sizeof(*cfg->pmk_list), GFP_KERNEL);
        if (!cfg->pmk_list)
                goto init_priv_mem_out;
@@ -4813,149 +4264,22 @@ init_priv_mem_out:
        return -ENOMEM;
 }
 
-/*
-* retrieve first queued event from head
-*/
-
-static struct brcmf_cfg80211_event_q *brcmf_deq_event(
-       struct brcmf_cfg80211_info *cfg)
-{
-       struct brcmf_cfg80211_event_q *e = NULL;
-
-       spin_lock_irq(&cfg->evt_q_lock);
-       if (!list_empty(&cfg->evt_q_list)) {
-               e = list_first_entry(&cfg->evt_q_list,
-                                    struct brcmf_cfg80211_event_q, evt_q_list);
-               list_del(&e->evt_q_list);
-       }
-       spin_unlock_irq(&cfg->evt_q_lock);
-
-       return e;
-}
-
-/*
-*      push event to tail of the queue
-*
-*      remark: this function may not sleep as it is called in atomic context.
-*/
-
-static s32
-brcmf_enq_event(struct brcmf_cfg80211_info *cfg, u32 event,
-               const struct brcmf_event_msg *msg, void *data)
-{
-       struct brcmf_cfg80211_event_q *e;
-       s32 err = 0;
-       ulong flags;
-       u32 data_len;
-       u32 total_len;
-
-       total_len = sizeof(struct brcmf_cfg80211_event_q);
-       if (data)
-               data_len = be32_to_cpu(msg->datalen);
-       else
-               data_len = 0;
-       total_len += data_len;
-       e = kzalloc(total_len, GFP_ATOMIC);
-       if (!e)
-               return -ENOMEM;
-
-       e->etype = event;
-       memcpy(&e->emsg, msg, sizeof(struct brcmf_event_msg));
-       if (data)
-               memcpy(&e->edata, data, data_len);
-
-       spin_lock_irqsave(&cfg->evt_q_lock, flags);
-       list_add_tail(&e->evt_q_list, &cfg->evt_q_list);
-       spin_unlock_irqrestore(&cfg->evt_q_lock, flags);
-
-       return err;
-}
-
-static void brcmf_put_event(struct brcmf_cfg80211_event_q *e)
-{
-       kfree(e);
-}
-
-static void brcmf_cfg80211_event_handler(struct work_struct *work)
-{
-       struct brcmf_cfg80211_info *cfg =
-                       container_of(work, struct brcmf_cfg80211_info,
-                                    event_work);
-       struct brcmf_cfg80211_event_q *e;
-
-       e = brcmf_deq_event(cfg);
-       if (unlikely(!e)) {
-               WL_ERR("event queue empty...\n");
-               return;
-       }
-
-       do {
-               WL_INFO("event type (%d)\n", e->etype);
-               if (cfg->el.handler[e->etype])
-                       cfg->el.handler[e->etype](cfg,
-                                                      cfg_to_ndev(cfg),
-                                                      &e->emsg, e->edata);
-               else
-                       WL_INFO("Unknown Event (%d): ignoring\n", e->etype);
-               brcmf_put_event(e);
-       } while ((e = brcmf_deq_event(cfg)));
-
-}
-
-static void brcmf_init_eq(struct brcmf_cfg80211_info *cfg)
-{
-       spin_lock_init(&cfg->evt_q_lock);
-       INIT_LIST_HEAD(&cfg->evt_q_list);
-}
-
-static void brcmf_flush_eq(struct brcmf_cfg80211_info *cfg)
-{
-       struct brcmf_cfg80211_event_q *e;
-
-       spin_lock_irq(&cfg->evt_q_lock);
-       while (!list_empty(&cfg->evt_q_list)) {
-               e = list_first_entry(&cfg->evt_q_list,
-                                    struct brcmf_cfg80211_event_q, evt_q_list);
-               list_del(&e->evt_q_list);
-               kfree(e);
-       }
-       spin_unlock_irq(&cfg->evt_q_lock);
-}
-
 static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
 {
        s32 err = 0;
 
        cfg->scan_request = NULL;
        cfg->pwr_save = true;
-#ifdef CONFIG_BRCMISCAN
-       cfg->iscan_on = true;   /* iscan on & off switch.
-                                we enable iscan per default */
-       cfg->escan_on = false;  /* escan on & off switch.
-                                we disable escan per default */
-#else
-       cfg->iscan_on = false;  /* iscan on & off switch.
-                                we disable iscan per default */
-       cfg->escan_on = true;   /* escan on & off switch.
-                                we enable escan per default */
-#endif
        cfg->roam_on = true;    /* roam on & off switch.
                                 we enable roam per default */
-
-       cfg->iscan_kickstart = false;
        cfg->active_scan = true;        /* we do active scan for
                                 specific scan per default */
        cfg->dongle_up = false; /* dongle is not up yet */
-       brcmf_init_eq(cfg);
        err = brcmf_init_priv_mem(cfg);
        if (err)
                return err;
-       INIT_WORK(&cfg->event_work, brcmf_cfg80211_event_handler);
-       brcmf_init_eloop_handler(&cfg->el);
+       brcmf_register_event_handlers(cfg);
        mutex_init(&cfg->usr_sync);
-       err = brcmf_init_iscan(cfg);
-       if (err)
-               return err;
        brcmf_init_escan(cfg);
        brcmf_init_conf(cfg->conf);
        brcmf_link_down(cfg);
@@ -4965,9 +4289,7 @@ static s32 wl_init_priv(struct brcmf_cfg80211_info *cfg)
 
 static void wl_deinit_priv(struct brcmf_cfg80211_info *cfg)
 {
-       cancel_work_sync(&cfg->event_work);
        cfg->dongle_up = false; /* dongle down */
-       brcmf_flush_eq(cfg);
        brcmf_link_down(cfg);
        brcmf_abort_scanning(cfg);
        brcmf_deinit_priv_mem(cfg);
@@ -5029,66 +4351,6 @@ void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg)
        }
 }
 
-void
-brcmf_cfg80211_event(struct net_device *ndev,
-                 const struct brcmf_event_msg *e, void *data)
-{
-       u32 event_type = be32_to_cpu(e->event_type);
-       struct brcmf_cfg80211_info *cfg = ndev_to_cfg(ndev);
-
-       if (!brcmf_enq_event(cfg, event_type, e, data))
-               schedule_work(&cfg->event_work);
-}
-
-static s32 brcmf_dongle_eventmsg(struct net_device *ndev)
-{
-       s8 eventmask[BRCMF_EVENTING_MASK_LEN];
-       s32 err = 0;
-
-       WL_TRACE("Enter\n");
-
-       /* Setup event_msgs */
-       err = brcmf_fil_iovar_data_get(netdev_priv(ndev), "event_msgs",
-                                      eventmask, BRCMF_EVENTING_MASK_LEN);
-       if (err) {
-               WL_ERR("Get event_msgs error (%d)\n", err);
-               goto dongle_eventmsg_out;
-       }
-
-       setbit(eventmask, BRCMF_E_SET_SSID);
-       setbit(eventmask, BRCMF_E_ROAM);
-       setbit(eventmask, BRCMF_E_PRUNE);
-       setbit(eventmask, BRCMF_E_AUTH);
-       setbit(eventmask, BRCMF_E_REASSOC);
-       setbit(eventmask, BRCMF_E_REASSOC_IND);
-       setbit(eventmask, BRCMF_E_DEAUTH_IND);
-       setbit(eventmask, BRCMF_E_DISASSOC_IND);
-       setbit(eventmask, BRCMF_E_DISASSOC);
-       setbit(eventmask, BRCMF_E_JOIN);
-       setbit(eventmask, BRCMF_E_ASSOC_IND);
-       setbit(eventmask, BRCMF_E_PSK_SUP);
-       setbit(eventmask, BRCMF_E_LINK);
-       setbit(eventmask, BRCMF_E_NDIS_LINK);
-       setbit(eventmask, BRCMF_E_MIC_ERROR);
-       setbit(eventmask, BRCMF_E_PMKID_CACHE);
-       setbit(eventmask, BRCMF_E_TXFAIL);
-       setbit(eventmask, BRCMF_E_JOIN_START);
-       setbit(eventmask, BRCMF_E_SCAN_COMPLETE);
-       setbit(eventmask, BRCMF_E_ESCAN_RESULT);
-       setbit(eventmask, BRCMF_E_PFN_NET_FOUND);
-
-       err = brcmf_fil_iovar_data_set(netdev_priv(ndev), "event_msgs",
-                                      eventmask, BRCMF_EVENTING_MASK_LEN);
-       if (err) {
-               WL_ERR("Set event_msgs error (%d)\n", err);
-               goto dongle_eventmsg_out;
-       }
-
-dongle_eventmsg_out:
-       WL_TRACE("Exit\n");
-       return err;
-}
-
 static s32
 brcmf_dongle_roam(struct net_device *ndev, u32 roamvar, u32 bcn_timeout)
 {
@@ -5190,7 +4452,7 @@ static s32 wl_update_wiphybands(struct brcmf_cfg80211_info *cfg)
        s8 phy;
        s32 err = 0;
 
-       err = brcmf_fil_cmd_data_get(ifp, BRCM_GET_PHYLIST,
+       err = brcmf_fil_cmd_data_get(ifp, BRCMF_C_GET_PHYLIST,
                                     &phy_list, sizeof(phy_list));
        if (err) {
                WL_ERR("error (%d)\n", err);
@@ -5228,10 +4490,6 @@ static s32 brcmf_config_dongle(struct brcmf_cfg80211_info *cfg)
        brcmf_dongle_scantime(ndev, WL_SCAN_CHANNEL_TIME,
                        WL_SCAN_UNASSOC_TIME, WL_SCAN_PASSIVE_TIME);
 
-       err = brcmf_dongle_eventmsg(ndev);
-       if (err)
-               goto default_conf_out;
-
        power_mode = cfg->pwr_save ? PM_FAST : PM_OFF;
        err = brcmf_fil_cmd_int_set(netdev_priv(ndev), BRCMF_C_SET_PM,
                                    power_mode);
@@ -5262,26 +4520,18 @@ default_conf_out:
 
 }
 
-static s32 __brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
+static s32 __brcmf_cfg80211_up(struct brcmf_if *ifp)
 {
-       struct brcmf_if *ifp = netdev_priv(cfg_to_ndev(cfg));
-       s32 err = 0;
-
        set_bit(BRCMF_VIF_STATUS_READY, &ifp->vif->sme_state);
+       if (ifp->idx)
+               return 0;
 
-       err = brcmf_config_dongle(cfg);
-       if (err)
-               return err;
-
-       brcmf_invoke_iscan(cfg);
-
-       return err;
+       return brcmf_config_dongle(ifp->drvr->config);
 }
 
-static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
+static s32 __brcmf_cfg80211_down(struct brcmf_if *ifp)
 {
-       struct net_device *ndev = cfg_to_ndev(cfg);
-       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
 
        /*
         * While going down, if associated with AP disassociate
@@ -5306,23 +4556,27 @@ static s32 __brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
        return 0;
 }
 
-s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg)
+s32 brcmf_cfg80211_up(struct net_device *ndev)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        s32 err = 0;
 
        mutex_lock(&cfg->usr_sync);
-       err = __brcmf_cfg80211_up(cfg);
+       err = __brcmf_cfg80211_up(ifp);
        mutex_unlock(&cfg->usr_sync);
 
        return err;
 }
 
-s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg)
+s32 brcmf_cfg80211_down(struct net_device *ndev)
 {
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       struct brcmf_cfg80211_info *cfg = ifp->drvr->config;
        s32 err = 0;
 
        mutex_lock(&cfg->usr_sync);
-       err = __brcmf_cfg80211_down(cfg);
+       err = __brcmf_cfg80211_down(ifp);
        mutex_unlock(&cfg->usr_sync);
 
        return err;
index 1dd96f148ef7e8eb9a2978c1d2e0f7be09c16cb9..e2ef8519ea8499076546f1cb85edf8923aa6d449 100644 (file)
@@ -84,31 +84,12 @@ do {                                                                \
 #define        WL_CONN(fmt, args...)
 #endif /* (defined DEBUG) */
 
-#define WL_NUM_SCAN_MAX                1
-#define WL_NUM_PMKIDS_MAX      MAXPMKID        /* will be used
-                                                * for 2.6.33 kernel
-                                                * or later
-                                                */
-#define WL_SCAN_BUF_MAX                        (1024 * 8)
+#define WL_NUM_SCAN_MAX                        10
+#define WL_NUM_PMKIDS_MAX              MAXPMKID
 #define WL_TLV_INFO_MAX                        1024
 #define WL_BSS_INFO_MAX                        2048
-#define WL_ASSOC_INFO_MAX      512     /*
-                                * needs to grab assoc info from dongle to
-                                * report it to cfg80211 through "connect"
-                                * event
-                                */
-#define WL_DCMD_LEN_MAX        1024
-#define WL_EXTRA_BUF_MAX       2048
-#define WL_ISCAN_BUF_MAX       2048    /*
-                                * the buf length can be BRCMF_DCMD_MAXLEN
-                                * to reduce iteration
-                                */
-#define WL_ISCAN_TIMER_INTERVAL_MS     3000
-#define WL_SCAN_ERSULTS_LAST   (BRCMF_SCAN_RESULTS_NO_MEM+1)
-#define WL_AP_MAX      256     /* virtually unlimitted as long
-                                * as kernel memory allows
-                                */
-
+#define WL_ASSOC_INFO_MAX              512     /* assoc related fil max buf */
+#define WL_EXTRA_BUF_MAX               2048
 #define WL_ROAM_TRIGGER_LEVEL          -75
 #define WL_ROAM_DELTA                  20
 #define WL_BEACON_TIMEOUT              3
@@ -145,12 +126,6 @@ enum wl_mode {
        WL_MODE_AP
 };
 
-/* dongle iscan state */
-enum wl_iscan_state {
-       WL_ISCAN_STATE_IDLE,
-       WL_ISCAN_STATE_SCANING
-};
-
 /* dongle configuration */
 struct brcmf_cfg80211_conf {
        u32 mode;               /* adhoc , infrastructure or ap */
@@ -162,17 +137,6 @@ struct brcmf_cfg80211_conf {
        struct ieee80211_channel channel;
 };
 
-/* forward declaration */
-struct brcmf_cfg80211_info;
-
-/* cfg80211 main event loop */
-struct brcmf_cfg80211_event_loop {
-       s32(*handler[BRCMF_E_LAST]) (struct brcmf_cfg80211_info *cfg,
-                                    struct net_device *ndev,
-                                    const struct brcmf_event_msg *e,
-                                    void *data);
-};
-
 /* basic structure of scan request */
 struct brcmf_cfg80211_scan_req {
        struct brcmf_ssid_le ssid_le;
@@ -184,14 +148,6 @@ struct brcmf_cfg80211_ie {
        u8 buf[WL_TLV_INFO_MAX];
 };
 
-/* event queue for cfg80211 main event */
-struct brcmf_cfg80211_event_q {
-       struct list_head evt_q_list;
-       u32 etype;
-       struct brcmf_event_msg emsg;
-       s8 edata[1];
-};
-
 /* security information with currently associated ap */
 struct brcmf_cfg80211_security {
        u32 wpa_versions;
@@ -270,26 +226,6 @@ struct brcmf_cfg80211_vif {
        struct list_head list;
 };
 
-/* dongle iscan event loop */
-struct brcmf_cfg80211_iscan_eloop {
-       s32 (*handler[WL_SCAN_ERSULTS_LAST])
-               (struct brcmf_cfg80211_info *cfg);
-};
-
-/* dongle iscan controller */
-struct brcmf_cfg80211_iscan_ctrl {
-       struct net_device *ndev;
-       struct timer_list timer;
-       u32 timer_ms;
-       u32 timer_on;
-       s32 state;
-       struct work_struct work;
-       struct brcmf_cfg80211_iscan_eloop el;
-       void *data;
-       s8 dcmd_buf[BRCMF_DCMD_SMLEN];
-       s8 scan_buf[WL_ISCAN_BUF_MAX];
-};
-
 /* association inform */
 struct brcmf_cfg80211_connect_info {
        u8 *req_ie;
@@ -323,17 +259,6 @@ struct escan_info {
        struct net_device *ndev;
 };
 
-/* Structure to hold WPS, WPA IEs for a AP */
-struct ap_info {
-       u8 probe_res_ie[IE_MAX_LEN];
-       u8 beacon_ie[IE_MAX_LEN];
-       u32 probe_res_ie_len;
-       u32 beacon_ie_len;
-       u8 *wpa_ie;
-       u8 *rsn_ie;
-       bool security_mode;
-};
-
 /**
  * struct brcmf_pno_param_le - PNO scan configuration parameters
  *
@@ -421,24 +346,16 @@ struct brcmf_pno_scanresults_le {
  * @wiphy: wiphy object for cfg80211 interface.
  * @conf: dongle configuration.
  * @scan_request: cfg80211 scan request object.
- * @el: main event loop.
- * @evt_q_list: used for event queue.
- * @evt_q_lock: for event queue synchronization.
  * @usr_sync: mainly for dongle up/down synchronization.
  * @bss_list: bss_list holding scanned ap information.
- * @scan_results: results of the last scan.
  * @scan_req_int: internal scan request object.
  * @bss_info: bss information for cfg80211 layer.
  * @ie: information element object for internal purpose.
- * @iscan: iscan controller information.
  * @conn_info: association info.
  * @pmk_list: wpa2 pmk list.
- * @event_work: event handler work struct.
  * @scan_status: scan activity on the dongle.
  * @pub: common driver information.
  * @channel: current channel.
- * @iscan_on: iscan on/off switch.
- * @iscan_kickstart: indicate iscan already started.
  * @active_scan: current scan mode.
  * @sched_escan: e-scan for scheduled scan support running.
  * @ibss_starter: indicates this sta is ibss starter.
@@ -450,12 +367,10 @@ struct brcmf_pno_scanresults_le {
  * @dcmd_buf: dcmd buffer.
  * @extra_buf: mainly to grab assoc information.
  * @debugfsdir: debugfs folder for this device.
- * @escan_on: escan on/off switch.
  * @escan_info: escan information.
  * @escan_timeout: Timer for catch scan timeout.
  * @escan_timeout_work: scan timeout worker.
  * @escan_ioctl_buf: dongle command buffer for escan commands.
- * @ap_info: host ap information.
  * @vif_list: linked list of vif instances.
  * @vif_cnt: number of vif instances.
  */
@@ -463,24 +378,16 @@ struct brcmf_cfg80211_info {
        struct wiphy *wiphy;
        struct brcmf_cfg80211_conf *conf;
        struct cfg80211_scan_request *scan_request;
-       struct brcmf_cfg80211_event_loop el;
-       struct list_head evt_q_list;
-       spinlock_t       evt_q_lock;
        struct mutex usr_sync;
        struct brcmf_scan_results *bss_list;
-       struct brcmf_scan_results *scan_results;
-       struct brcmf_cfg80211_scan_req *scan_req_int;
+       struct brcmf_cfg80211_scan_req scan_req_int;
        struct wl_cfg80211_bss_info *bss_info;
        struct brcmf_cfg80211_ie ie;
-       struct brcmf_cfg80211_iscan_ctrl *iscan;
        struct brcmf_cfg80211_connect_info conn_info;
        struct brcmf_cfg80211_pmk_list *pmk_list;
-       struct work_struct event_work;
        unsigned long scan_status;
        struct brcmf_pub *pub;
        u32 channel;
-       bool iscan_on;
-       bool iscan_kickstart;
        bool active_scan;
        bool sched_escan;
        bool ibss_starter;
@@ -492,12 +399,10 @@ struct brcmf_cfg80211_info {
        u8 *dcmd_buf;
        u8 *extra_buf;
        struct dentry *debugfsdir;
-       bool escan_on;
        struct escan_info escan_info;
        struct timer_list escan_timeout;
        struct work_struct escan_timeout_work;
        u8 *escan_ioctl_buf;
-       struct ap_info *ap_info;
        struct list_head vif_list;
        u8 vif_cnt;
 };
@@ -536,8 +441,11 @@ static inline struct brcmf_cfg80211_profile *ndev_to_prof(struct net_device *nd)
        return &ifp->vif->profile;
 }
 
-#define iscan_to_cfg(i) ((struct brcmf_cfg80211_info *)(i->data))
-#define cfg_to_iscan(w) (w->iscan)
+static inline struct brcmf_cfg80211_vif *ndev_to_vif(struct net_device *ndev)
+{
+       struct brcmf_if *ifp = netdev_priv(ndev);
+       return ifp->vif;
+}
 
 static inline struct
 brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
@@ -547,11 +455,7 @@ brcmf_cfg80211_connect_info *cfg_to_conn(struct brcmf_cfg80211_info *cfg)
 
 struct brcmf_cfg80211_info *brcmf_cfg80211_attach(struct brcmf_pub *drvr);
 void brcmf_cfg80211_detach(struct brcmf_cfg80211_info *cfg);
-
-/* event handler from dongle */
-void brcmf_cfg80211_event(struct net_device *ndev,
-                         const struct brcmf_event_msg *e, void *data);
-s32 brcmf_cfg80211_up(struct brcmf_cfg80211_info *cfg);
-s32 brcmf_cfg80211_down(struct brcmf_cfg80211_info *cfg);
+s32 brcmf_cfg80211_up(struct net_device *ndev);
+s32 brcmf_cfg80211_down(struct net_device *ndev);
 
 #endif                         /* _wl_cfg80211_h_ */
index e227c4c68ef943e74eb4c35026a9fc397a2f186d..d3d4151c3eda8bdd94f06110f465bfba98a96cea 100644 (file)
@@ -40,7 +40,8 @@ BRCMSMAC_OFILES := \
        phy/phytbl_n.o \
        phy/phy_qmath.o \
        dma.o \
-       brcms_trace_events.o
+       brcms_trace_events.o \
+       debug.o
 
 MODULEPFX := brcmsmac
 
index be5bcfb9153bfacca71e4cd226fa2c0224612334..1de94f30564fe8291c99657ced06d33ff6af2e5b 100644 (file)
@@ -21,6 +21,8 @@
 #include "antsel.h"
 #include "main.h"
 #include "ampdu.h"
+#include "debug.h"
+#include "brcms_trace_events.h"
 
 /* max number of mpdus in an ampdu */
 #define AMPDU_MAX_MPDU                 32
@@ -40,8 +42,6 @@
 #define AMPDU_DEF_RETRY_LIMIT          5
 /* default tx retry limit at reg rate */
 #define AMPDU_DEF_RR_RETRY_LIMIT       2
-/* default weight of ampdu in txfifo */
-#define AMPDU_DEF_TXPKT_WEIGHT         2
 /* default ffpld reserved bytes */
 #define AMPDU_DEF_FFPLD_RSVD           2048
 /* # of inis to be freed on detach */
@@ -114,7 +114,6 @@ struct brcms_fifo_info {
  * mpdu_density: min mpdu spacing (0-7) ==> 2^(x-1)/8 usec
  * max_pdu: max pdus allowed in ampdu
  * dur: max duration of an ampdu (in msec)
- * txpkt_weight: weight of ampdu in txfifo; reduces rate lag
  * rx_factor: maximum rx ampdu factor (0-3) ==> 2^(13+x) bytes
  * ffpld_rsvd: number of bytes to reserve for preload
  * max_txlen: max size of ampdu per mcs, bw and sgi
@@ -136,7 +135,6 @@ struct ampdu_info {
        u8 mpdu_density;
        s8 max_pdu;
        u8 dur;
-       u8 txpkt_weight;
        u8 rx_factor;
        u32 ffpld_rsvd;
        u32 max_txlen[MCS_TABLE_SIZE][2][2];
@@ -183,18 +181,19 @@ static bool brcms_c_ampdu_cap(struct ampdu_info *ampdu)
 static int brcms_c_ampdu_set(struct ampdu_info *ampdu, bool on)
 {
        struct brcms_c_info *wlc = ampdu->wlc;
+       struct bcma_device *core = wlc->hw->d11core;
 
        wlc->pub->_ampdu = false;
 
        if (on) {
                if (!(wlc->pub->_n_enab & SUPPORT_11N)) {
-                       wiphy_err(ampdu->wlc->wiphy, "wl%d: driver not "
-                               "nmode enabled\n", wlc->pub->unit);
+                       brcms_err(core, "wl%d: driver not nmode enabled\n",
+                                 wlc->pub->unit);
                        return -ENOTSUPP;
                }
                if (!brcms_c_ampdu_cap(ampdu)) {
-                       wiphy_err(ampdu->wlc->wiphy, "wl%d: device not "
-                               "ampdu capable\n", wlc->pub->unit);
+                       brcms_err(core, "wl%d: device not ampdu capable\n",
+                                 wlc->pub->unit);
                        return -ENOTSUPP;
                }
                wlc->pub->_ampdu = on;
@@ -247,7 +246,6 @@ struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc)
        ampdu->mpdu_density = AMPDU_DEF_MPDU_DENSITY;
        ampdu->max_pdu = AUTO;
        ampdu->dur = AMPDU_MAX_DUR;
-       ampdu->txpkt_weight = AMPDU_DEF_TXPKT_WEIGHT;
 
        ampdu->ffpld_rsvd = AMPDU_DEF_FFPLD_RSVD;
        /*
@@ -374,7 +372,8 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
                                      offsetof(struct macstat, txfunfl[fid]));
        new_txunfl = (u16) (cur_txunfl - fifo->prev_txfunfl);
        if (new_txunfl == 0) {
-               BCMMSG(wlc->wiphy, "TX status FRAG set but no tx underflows\n");
+               brcms_dbg_ht(wlc->hw->d11core,
+                            "TX status FRAG set but no tx underflows\n");
                return -1;
        }
        fifo->prev_txfunfl = cur_txunfl;
@@ -396,8 +395,8 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
        if (fifo->accum_txfunfl < 10)
                return 0;
 
-       BCMMSG(wlc->wiphy, "ampdu_count %d  tx_underflows %d\n",
-               current_ampdu_cnt, fifo->accum_txfunfl);
+       brcms_dbg_ht(wlc->hw->d11core, "ampdu_count %d  tx_underflows %d\n",
+                    current_ampdu_cnt, fifo->accum_txfunfl);
 
        /*
           compute the current ratio of tx unfl per ampdu.
@@ -450,9 +449,10 @@ static int brcms_c_ffpld_check_txfunfl(struct brcms_c_info *wlc, int fid)
                      (max_mpdu * FFPLD_MPDU_SIZE - fifo->ampdu_pld_size))
                     / (max_mpdu * FFPLD_MPDU_SIZE)) * 100;
 
-               BCMMSG(wlc->wiphy, "DMA estimated transfer rate %d; "
-                       "pre-load size %d\n",
-                       fifo->dmaxferrate, fifo->ampdu_pld_size);
+               brcms_dbg_ht(wlc->hw->d11core,
+                            "DMA estimated transfer rate %d; "
+                            "pre-load size %d\n",
+                            fifo->dmaxferrate, fifo->ampdu_pld_size);
        } else {
 
                /* decrease ampdu size */
@@ -486,7 +486,7 @@ brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
        scb_ampdu = &scb->scb_ampdu;
 
        if (!ampdu->ini_enable[tid]) {
-               wiphy_err(ampdu->wlc->wiphy, "%s: Rejecting tid %d\n",
+               brcms_err(wlc->hw->d11core, "%s: Rejecting tid %d\n",
                          __func__, tid);
                return;
        }
@@ -498,378 +498,324 @@ brcms_c_ampdu_tx_operational(struct brcms_c_info *wlc, u8 tid,
        scb_ampdu->max_rx_ampdu_bytes = max_rx_ampdu_bytes;
 }
 
-int
-brcms_c_sendampdu(struct ampdu_info *ampdu, struct brcms_txq_info *qi,
-             struct sk_buff **pdu, int prec)
+void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session,
+                                struct brcms_c_info *wlc)
 {
-       struct brcms_c_info *wlc;
-       struct sk_buff *p, *pkt[AMPDU_MAX_MPDU];
-       u8 tid, ndelim;
-       int err = 0;
-       u8 preamble_type = BRCMS_GF_PREAMBLE;
-       u8 fbr_preamble_type = BRCMS_GF_PREAMBLE;
-       u8 rts_preamble_type = BRCMS_LONG_PREAMBLE;
-       u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE;
+       session->wlc = wlc;
+       skb_queue_head_init(&session->skb_list);
+       session->max_ampdu_len = 0;    /* determined from first MPDU */
+       session->max_ampdu_frames = 0; /* determined from first MPDU */
+       session->ampdu_len = 0;
+       session->dma_len = 0;
+}
 
-       bool rr = true, fbr = false;
-       uint i, count = 0, fifo, seg_cnt = 0;
-       u16 plen, len, seq = 0, mcl, mch, index, frameid, dma_len = 0;
-       u32 ampdu_len, max_ampdu_bytes = 0;
-       struct d11txh *txh = NULL;
+/*
+ * Preps the given packet for AMPDU based on the session data. If the
+ * frame cannot be accomodated in the current session, -ENOSPC is
+ * returned.
+ */
+int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,
+                           struct sk_buff *p)
+{
+       struct brcms_c_info *wlc = session->wlc;
+       struct ampdu_info *ampdu = wlc->ampdu;
+       struct scb *scb = &wlc->pri_scb;
+       struct scb_ampdu *scb_ampdu = &scb->scb_ampdu;
+       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
+       struct ieee80211_tx_rate *txrate = tx_info->status.rates;
+       struct d11txh *txh = (struct d11txh *)p->data;
+       unsigned ampdu_frames;
+       u8 ndelim, tid;
        u8 *plcp;
-       struct ieee80211_hdr *h;
-       struct scb *scb;
-       struct scb_ampdu *scb_ampdu;
-       struct scb_ampdu_tid_ini *ini;
-       u8 mcs = 0;
-       bool use_rts = false, use_cts = false;
-       u32 rspec = 0, rspec_fallback = 0;
-       u32 rts_rspec = 0, rts_rspec_fallback = 0;
-       u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
-       struct ieee80211_rts *rts;
-       u8 rr_retry_limit;
-       struct brcms_fifo_info *f;
+       uint len;
+       u16 mcl;
        bool fbr_iscck;
-       struct ieee80211_tx_info *tx_info;
-       u16 qlen;
-       struct wiphy *wiphy;
-
-       wlc = ampdu->wlc;
-       wiphy = wlc->wiphy;
-       p = *pdu;
-
-       tid = (u8) (p->priority);
+       bool rr;
 
-       f = ampdu->fifo_tb + prio2fifo[tid];
+       ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
+       plcp = (u8 *)(txh + 1);
+       fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03);
+       len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) :
+                         BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
+       len = roundup(len, 4) + (ndelim + 1) * AMPDU_DELIMITER_LEN;
 
-       scb = &wlc->pri_scb;
-       scb_ampdu = &scb->scb_ampdu;
-       ini = &scb_ampdu->ini[tid];
+       ampdu_frames = skb_queue_len(&session->skb_list);
+       if (ampdu_frames != 0) {
+               struct sk_buff *first;
 
-       /* Let pressure continue to build ... */
-       qlen = pktq_plen(&qi->q, prec);
-       if (ini->tx_in_transit > 0 &&
-           qlen < min(scb_ampdu->max_pdu, ini->ba_wsize))
-               /* Collect multiple MPDU's to be sent in the next AMPDU */
-               return -EBUSY;
+               if (ampdu_frames + 1 > session->max_ampdu_frames ||
+                   session->ampdu_len + len > session->max_ampdu_len)
+                       return -ENOSPC;
 
-       /* at this point we intend to transmit an AMPDU */
-       rr_retry_limit = ampdu->rr_retry_limit_tid[tid];
-       ampdu_len = 0;
-       dma_len = 0;
-       while (p) {
-               struct ieee80211_tx_rate *txrate;
-
-               tx_info = IEEE80211_SKB_CB(p);
-               txrate = tx_info->status.rates;
+               /*
+                * We aren't really out of space if the new frame is of
+                * a different priority, but we want the same behaviour
+                * so return -ENOSPC anyway.
+                *
+                * XXX: The old AMPDU code did this, but is it really
+                * necessary?
+                */
+               first = skb_peek(&session->skb_list);
+               if (p->priority != first->priority)
+                       return -ENOSPC;
+       }
 
-               if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       err = brcms_c_prep_pdu(wlc, p, &fifo);
-               } else {
-                       wiphy_err(wiphy, "%s: AMPDU flag is off!\n", __func__);
-                       *pdu = NULL;
-                       err = 0;
-                       break;
-               }
+       /*
+        * Now that we're sure this frame can be accomodated, update the
+        * session information.
+        */
+       session->ampdu_len += len;
+       session->dma_len += p->len;
 
-               if (err) {
-                       if (err == -EBUSY) {
-                               wiphy_err(wiphy, "wl%d: sendampdu: "
-                                         "prep_xdu retry; seq 0x%x\n",
-                                         wlc->pub->unit, seq);
-                               *pdu = p;
-                               break;
-                       }
+       tid = (u8)p->priority;
 
-                       /* error in the packet; reject it */
-                       wiphy_err(wiphy, "wl%d: sendampdu: prep_xdu "
-                                 "rejected; seq 0x%x\n", wlc->pub->unit, seq);
-                       *pdu = NULL;
-                       break;
-               }
+       /* Handle retry limits */
+       if (txrate[0].count <= ampdu->rr_retry_limit_tid[tid]) {
+               txrate[0].count++;
+               rr = true;
+       } else {
+               txrate[1].count++;
+               rr = false;
+       }
 
-               /* pkt is good to be aggregated */
-               txh = (struct d11txh *) p->data;
-               plcp = (u8 *) (txh + 1);
-               h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
-               seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
-               index = TX_SEQ_TO_INDEX(seq);
+       if (ampdu_frames == 0) {
+               u8 plcp0, plcp3, is40, sgi, mcs;
+               uint fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
+               struct brcms_fifo_info *f = &ampdu->fifo_tb[fifo];
 
-               /* check mcl fields and test whether it can be agg'd */
-               mcl = le16_to_cpu(txh->MacTxControlLow);
-               mcl &= ~TXC_AMPDU_MASK;
-               fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x3);
-               txh->PreloadSize = 0;   /* always default to 0 */
-
-               /*  Handle retry limits */
-               if (txrate[0].count <= rr_retry_limit) {
-                       txrate[0].count++;
-                       rr = true;
-                       fbr = false;
+               if (rr) {
+                       plcp0 = plcp[0];
+                       plcp3 = plcp[3];
                } else {
-                       fbr = true;
-                       rr = false;
-                       txrate[1].count++;
-               }
-
-               /* extract the length info */
-               len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
-                   : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
-
-               /* retrieve null delimiter count */
-               ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
-               seg_cnt += 1;
+                       plcp0 = txh->FragPLCPFallback[0];
+                       plcp3 = txh->FragPLCPFallback[3];
 
-               BCMMSG(wlc->wiphy, "wl%d: mpdu %d plcp_len %d\n",
-                       wlc->pub->unit, count, len);
-
-               /*
-                * aggregateable mpdu. For ucode/hw agg,
-                * test whether need to break or change the epoch
-                */
-               if (count == 0) {
-                       mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
-                       /* refill the bits since might be a retx mpdu */
-                       mcl |= TXC_STARTMSDU;
-                       rts = (struct ieee80211_rts *)&txh->rts_frame;
-
-                       if (ieee80211_is_rts(rts->frame_control)) {
-                               mcl |= TXC_SENDRTS;
-                               use_rts = true;
-                       }
-                       if (ieee80211_is_cts(rts->frame_control)) {
-                               mcl |= TXC_SENDCTS;
-                               use_cts = true;
-                       }
-               } else {
-                       mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
-                       mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
                }
 
-               len = roundup(len, 4);
-               ampdu_len += (len + (ndelim + 1) * AMPDU_DELIMITER_LEN);
+               /* Limit AMPDU size based on MCS */
+               is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
+               sgi = plcp3_issgi(plcp3) ? 1 : 0;
+               mcs = plcp0 & ~MIMO_PLCP_40MHZ;
+               session->max_ampdu_len = min(scb_ampdu->max_rx_ampdu_bytes,
+                                            ampdu->max_txlen[mcs][is40][sgi]);
 
-               dma_len += (u16) p->len;
+               session->max_ampdu_frames = scb_ampdu->max_pdu;
+               if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
+                       session->max_ampdu_frames =
+                               min_t(u16, f->mcs2ampdu_table[mcs],
+                                     session->max_ampdu_frames);
+               }
+       }
 
-               BCMMSG(wlc->wiphy, "wl%d: ampdu_len %d"
-                       " seg_cnt %d null delim %d\n",
-                       wlc->pub->unit, ampdu_len, seg_cnt, ndelim);
+       /*
+        * Treat all frames as "middle" frames of AMPDU here. First and
+        * last frames must be fixed up after all MPDUs have been prepped.
+        */
+       mcl = le16_to_cpu(txh->MacTxControlLow);
+       mcl &= ~TXC_AMPDU_MASK;
+       mcl |= (TXC_AMPDU_MIDDLE << TXC_AMPDU_SHIFT);
+       mcl &= ~(TXC_STARTMSDU | TXC_SENDRTS | TXC_SENDCTS);
+       txh->MacTxControlLow = cpu_to_le16(mcl);
+       txh->PreloadSize = 0;   /* always default to 0 */
 
-               txh->MacTxControlLow = cpu_to_le16(mcl);
+       skb_queue_tail(&session->skb_list, p);
 
-               /* this packet is added */
-               pkt[count++] = p;
+       return 0;
+}
 
-               /* patch the first MPDU */
-               if (count == 1) {
-                       u8 plcp0, plcp3, is40, sgi;
+void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session)
+{
+       struct brcms_c_info *wlc = session->wlc;
+       struct ampdu_info *ampdu = wlc->ampdu;
+       struct sk_buff *first, *last;
+       struct d11txh *txh;
+       struct ieee80211_tx_info *tx_info;
+       struct ieee80211_tx_rate *txrate;
+       u8 ndelim;
+       u8 *plcp;
+       uint len;
+       uint fifo;
+       struct brcms_fifo_info *f;
+       u16 mcl;
+       bool fbr;
+       bool fbr_iscck;
+       struct ieee80211_rts *rts;
+       bool use_rts = false, use_cts = false;
+       u16 dma_len = session->dma_len;
+       u16 mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
+       u32 rspec = 0, rspec_fallback = 0;
+       u32 rts_rspec = 0, rts_rspec_fallback = 0;
+       u8 plcp0, plcp3, is40, sgi, mcs;
+       u16 mch;
+       u8 preamble_type = BRCMS_GF_PREAMBLE;
+       u8 fbr_preamble_type = BRCMS_GF_PREAMBLE;
+       u8 rts_preamble_type = BRCMS_LONG_PREAMBLE;
+       u8 rts_fbr_preamble_type = BRCMS_LONG_PREAMBLE;
 
-                       if (rr) {
-                               plcp0 = plcp[0];
-                               plcp3 = plcp[3];
-                       } else {
-                               plcp0 = txh->FragPLCPFallback[0];
-                               plcp3 = txh->FragPLCPFallback[3];
+       if (skb_queue_empty(&session->skb_list))
+               return;
 
-                       }
-                       is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
-                       sgi = plcp3_issgi(plcp3) ? 1 : 0;
-                       mcs = plcp0 & ~MIMO_PLCP_40MHZ;
-                       max_ampdu_bytes =
-                           min(scb_ampdu->max_rx_ampdu_bytes,
-                               ampdu->max_txlen[mcs][is40][sgi]);
-
-                       if (is40)
-                               mimo_ctlchbw =
-                                  CHSPEC_SB_UPPER(wlc_phy_chanspec_get(
-                                                                wlc->band->pi))
-                                  ? PHY_TXC1_BW_20MHZ_UP : PHY_TXC1_BW_20MHZ;
-
-                       /* rebuild the rspec and rspec_fallback */
-                       rspec = RSPEC_MIMORATE;
-                       rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
-                       if (plcp[0] & MIMO_PLCP_40MHZ)
-                               rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
-
-                       if (fbr_iscck)  /* CCK */
-                               rspec_fallback = cck_rspec(cck_phy2mac_rate
-                                                   (txh->FragPLCPFallback[0]));
-                       else {  /* MIMO */
-                               rspec_fallback = RSPEC_MIMORATE;
-                               rspec_fallback |=
-                                   txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
-                               if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
-                                       rspec_fallback |=
-                                           (PHY_TXC1_BW_40MHZ <<
-                                            RSPEC_BW_SHIFT);
-                       }
+       first = skb_peek(&session->skb_list);
+       last = skb_peek_tail(&session->skb_list);
+
+       /* Need to fix up last MPDU first to adjust AMPDU length */
+       txh = (struct d11txh *)last->data;
+       fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
+       f = &ampdu->fifo_tb[fifo];
+
+       mcl = le16_to_cpu(txh->MacTxControlLow);
+       mcl &= ~TXC_AMPDU_MASK;
+       mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
+       txh->MacTxControlLow = cpu_to_le16(mcl);
+
+       /* remove the null delimiter after last mpdu */
+       ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
+       txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
+       session->ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
+
+       /* remove the pad len from last mpdu */
+       fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
+       len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback) :
+                         BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
+       session->ampdu_len -= roundup(len, 4) - len;
+
+       /* Now fix up the first MPDU */
+       tx_info = IEEE80211_SKB_CB(first);
+       txrate = tx_info->status.rates;
+       txh = (struct d11txh *)first->data;
+       plcp = (u8 *)(txh + 1);
+       rts = (struct ieee80211_rts *)&txh->rts_frame;
+
+       mcl = le16_to_cpu(txh->MacTxControlLow);
+       /* If only one MPDU leave it marked as last */
+       if (first != last) {
+               mcl &= ~TXC_AMPDU_MASK;
+               mcl |= (TXC_AMPDU_FIRST << TXC_AMPDU_SHIFT);
+       }
+       mcl |= TXC_STARTMSDU;
+       if (ieee80211_is_rts(rts->frame_control)) {
+               mcl |= TXC_SENDRTS;
+               use_rts = true;
+       }
+       if (ieee80211_is_cts(rts->frame_control)) {
+               mcl |= TXC_SENDCTS;
+               use_cts = true;
+       }
+       txh->MacTxControlLow = cpu_to_le16(mcl);
 
-                       if (use_rts || use_cts) {
-                               rts_rspec =
-                                   brcms_c_rspec_to_rts_rspec(wlc,
-                                       rspec, false, mimo_ctlchbw);
-                               rts_rspec_fallback =
-                                   brcms_c_rspec_to_rts_rspec(wlc,
-                                       rspec_fallback, false, mimo_ctlchbw);
-                       }
-               }
+       fbr = txrate[1].count > 0;
+       if (!fbr) {
+               plcp0 = plcp[0];
+               plcp3 = plcp[3];
+       } else {
+               plcp0 = txh->FragPLCPFallback[0];
+               plcp3 = txh->FragPLCPFallback[3];
+       }
+       is40 = (plcp0 & MIMO_PLCP_40MHZ) ? 1 : 0;
+       sgi = plcp3_issgi(plcp3) ? 1 : 0;
+       mcs = plcp0 & ~MIMO_PLCP_40MHZ;
+
+       if (is40) {
+               if (CHSPEC_SB_UPPER(wlc_phy_chanspec_get(wlc->band->pi)))
+                       mimo_ctlchbw = PHY_TXC1_BW_20MHZ_UP;
+               else
+                       mimo_ctlchbw = PHY_TXC1_BW_20MHZ;
+       }
 
-               /* if (first mpdu for host agg) */
-               /* test whether to add more */
-               if ((mcs_2_rate(mcs, true, false) >= f->dmaxferrate) &&
-                   (count == f->mcs2ampdu_table[mcs])) {
-                       BCMMSG(wlc->wiphy, "wl%d: PR 37644: stopping"
-                               " ampdu at %d for mcs %d\n",
-                               wlc->pub->unit, count, mcs);
-                       break;
-               }
+       /* rebuild the rspec and rspec_fallback */
+       rspec = RSPEC_MIMORATE;
+       rspec |= plcp[0] & ~MIMO_PLCP_40MHZ;
+       if (plcp[0] & MIMO_PLCP_40MHZ)
+               rspec |= (PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT);
 
-               if (count == scb_ampdu->max_pdu)
-                       break;
+       fbr_iscck = !(le16_to_cpu(txh->XtraFrameTypes) & 0x03);
+       if (fbr_iscck) {
+               rspec_fallback =
+                       cck_rspec(cck_phy2mac_rate(txh->FragPLCPFallback[0]));
+       } else {
+               rspec_fallback = RSPEC_MIMORATE;
+               rspec_fallback |= txh->FragPLCPFallback[0] & ~MIMO_PLCP_40MHZ;
+               if (txh->FragPLCPFallback[0] & MIMO_PLCP_40MHZ)
+                       rspec_fallback |= PHY_TXC1_BW_40MHZ << RSPEC_BW_SHIFT;
+       }
 
-               /*
-                * check to see if the next pkt is
-                * a candidate for aggregation
-                */
-               p = pktq_ppeek(&qi->q, prec);
-               if (p) {
-                       tx_info = IEEE80211_SKB_CB(p);
-                       if ((tx_info->flags & IEEE80211_TX_CTL_AMPDU) &&
-                           ((u8) (p->priority) == tid)) {
-                               plen = p->len + AMPDU_MAX_MPDU_OVERHEAD;
-                               plen = max(scb_ampdu->min_len, plen);
+       if (use_rts || use_cts) {
+               rts_rspec =
+                       brcms_c_rspec_to_rts_rspec(wlc, rspec,
+                                                  false, mimo_ctlchbw);
+               rts_rspec_fallback =
+                       brcms_c_rspec_to_rts_rspec(wlc, rspec_fallback,
+                                                  false, mimo_ctlchbw);
+       }
 
-                               if ((plen + ampdu_len) > max_ampdu_bytes) {
-                                       p = NULL;
-                                       continue;
-                               }
+       BRCMS_SET_MIMO_PLCP_LEN(plcp, session->ampdu_len);
+       /* mark plcp to indicate ampdu */
+       BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
 
-                               /*
-                                * check if there are enough
-                                * descriptors available
-                                */
-                               if (*wlc->core->txavail[fifo] <= seg_cnt + 1) {
-                                       wiphy_err(wiphy, "%s: No fifo space  "
-                                                 "!!\n", __func__);
-                                       p = NULL;
-                                       continue;
-                               }
-                               /* next packet fit for aggregation so dequeue */
-                               p = brcmu_pktq_pdeq(&qi->q, prec);
-                       } else {
-                               p = NULL;
-                       }
-               }
-       }                       /* end while(p) */
+       /* reset the mixed mode header durations */
+       if (txh->MModeLen) {
+               u16 mmodelen = brcms_c_calc_lsig_len(wlc, rspec,
+                                                    session->ampdu_len);
+               txh->MModeLen = cpu_to_le16(mmodelen);
+               preamble_type = BRCMS_MM_PREAMBLE;
+       }
+       if (txh->MModeFbrLen) {
+               u16 mmfbrlen = brcms_c_calc_lsig_len(wlc, rspec_fallback,
+                                                    session->ampdu_len);
+               txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
+               fbr_preamble_type = BRCMS_MM_PREAMBLE;
+       }
 
-       ini->tx_in_transit += count;
+       /* set the preload length */
+       if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
+               dma_len = min(dma_len, f->ampdu_pld_size);
+               txh->PreloadSize = cpu_to_le16(dma_len);
+       } else {
+               txh->PreloadSize = 0;
+       }
 
-       if (count) {
-               /* patch up the last txh */
-               txh = (struct d11txh *) pkt[count - 1]->data;
-               mcl = le16_to_cpu(txh->MacTxControlLow);
-               mcl &= ~TXC_AMPDU_MASK;
-               mcl |= (TXC_AMPDU_LAST << TXC_AMPDU_SHIFT);
-               txh->MacTxControlLow = cpu_to_le16(mcl);
-
-               /* remove the null delimiter after last mpdu */
-               ndelim = txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM];
-               txh->RTSPLCPFallback[AMPDU_FBR_NULL_DELIM] = 0;
-               ampdu_len -= ndelim * AMPDU_DELIMITER_LEN;
-
-               /* remove the pad len from last mpdu */
-               fbr_iscck = ((le16_to_cpu(txh->XtraFrameTypes) & 0x3) == 0);
-               len = fbr_iscck ? BRCMS_GET_CCK_PLCP_LEN(txh->FragPLCPFallback)
-                   : BRCMS_GET_MIMO_PLCP_LEN(txh->FragPLCPFallback);
-               ampdu_len -= roundup(len, 4) - len;
-
-               /* patch up the first txh & plcp */
-               txh = (struct d11txh *) pkt[0]->data;
-               plcp = (u8 *) (txh + 1);
+       mch = le16_to_cpu(txh->MacTxControlHigh);
 
-               BRCMS_SET_MIMO_PLCP_LEN(plcp, ampdu_len);
-               /* mark plcp to indicate ampdu */
-               BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
+       /* update RTS dur fields */
+       if (use_rts || use_cts) {
+               u16 durid;
+               if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
+                   TXC_PREAMBLE_RTS_MAIN_SHORT)
+                       rts_preamble_type = BRCMS_SHORT_PREAMBLE;
 
-               /* reset the mixed mode header durations */
-               if (txh->MModeLen) {
-                       u16 mmodelen =
-                           brcms_c_calc_lsig_len(wlc, rspec, ampdu_len);
-                       txh->MModeLen = cpu_to_le16(mmodelen);
-                       preamble_type = BRCMS_MM_PREAMBLE;
-               }
-               if (txh->MModeFbrLen) {
-                       u16 mmfbrlen =
-                           brcms_c_calc_lsig_len(wlc, rspec_fallback,
-                                                 ampdu_len);
-                       txh->MModeFbrLen = cpu_to_le16(mmfbrlen);
-                       fbr_preamble_type = BRCMS_MM_PREAMBLE;
-               }
+               if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
+                    TXC_PREAMBLE_RTS_FB_SHORT)
+                       rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE;
 
-               /* set the preload length */
-               if (mcs_2_rate(mcs, true, false) >= f->dmaxferrate) {
-                       dma_len = min(dma_len, f->ampdu_pld_size);
-                       txh->PreloadSize = cpu_to_le16(dma_len);
-               } else
-                       txh->PreloadSize = 0;
-
-               mch = le16_to_cpu(txh->MacTxControlHigh);
-
-               /* update RTS dur fields */
-               if (use_rts || use_cts) {
-                       u16 durid;
-                       rts = (struct ieee80211_rts *)&txh->rts_frame;
-                       if ((mch & TXC_PREAMBLE_RTS_MAIN_SHORT) ==
-                           TXC_PREAMBLE_RTS_MAIN_SHORT)
-                               rts_preamble_type = BRCMS_SHORT_PREAMBLE;
-
-                       if ((mch & TXC_PREAMBLE_RTS_FB_SHORT) ==
-                           TXC_PREAMBLE_RTS_FB_SHORT)
-                               rts_fbr_preamble_type = BRCMS_SHORT_PREAMBLE;
-
-                       durid =
-                           brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec,
+               durid = brcms_c_compute_rtscts_dur(wlc, use_cts, rts_rspec,
                                                   rspec, rts_preamble_type,
-                                                  preamble_type, ampdu_len,
-                                                  true);
-                       rts->duration = cpu_to_le16(durid);
-                       durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
-                                                      rts_rspec_fallback,
-                                                      rspec_fallback,
-                                                      rts_fbr_preamble_type,
-                                                      fbr_preamble_type,
-                                                      ampdu_len, true);
-                       txh->RTSDurFallback = cpu_to_le16(durid);
-                       /* set TxFesTimeNormal */
-                       txh->TxFesTimeNormal = rts->duration;
-                       /* set fallback rate version of TxFesTimeNormal */
-                       txh->TxFesTimeFallback = txh->RTSDurFallback;
-               }
-
-               /* set flag and plcp for fallback rate */
-               if (fbr) {
-                       mch |= TXC_AMPDU_FBR;
-                       txh->MacTxControlHigh = cpu_to_le16(mch);
-                       BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
-                       BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
-               }
-
-               BCMMSG(wlc->wiphy, "wl%d: count %d ampdu_len %d\n",
-                       wlc->pub->unit, count, ampdu_len);
-
-               /* inform rate_sel if it this is a rate probe pkt */
-               frameid = le16_to_cpu(txh->TxFrameID);
-               if (frameid & TXFID_RATE_PROBE_MASK)
-                       wiphy_err(wiphy, "%s: XXX what to do with "
-                                 "TXFID_RATE_PROBE_MASK!?\n", __func__);
-
-               for (i = 0; i < count; i++)
-                       brcms_c_txfifo(wlc, fifo, pkt[i], i == (count - 1),
-                                  ampdu->txpkt_weight);
+                                                  preamble_type,
+                                                  session->ampdu_len, true);
+               rts->duration = cpu_to_le16(durid);
+               durid = brcms_c_compute_rtscts_dur(wlc, use_cts,
+                                                  rts_rspec_fallback,
+                                                  rspec_fallback,
+                                                  rts_fbr_preamble_type,
+                                                  fbr_preamble_type,
+                                                  session->ampdu_len, true);
+               txh->RTSDurFallback = cpu_to_le16(durid);
+               /* set TxFesTimeNormal */
+               txh->TxFesTimeNormal = rts->duration;
+               /* set fallback rate version of TxFesTimeNormal */
+               txh->TxFesTimeFallback = txh->RTSDurFallback;
+       }
 
+       /* set flag and plcp for fallback rate */
+       if (fbr) {
+               mch |= TXC_AMPDU_FBR;
+               txh->MacTxControlHigh = cpu_to_le16(mch);
+               BRCMS_SET_MIMO_PLCP_AMPDU(plcp);
+               BRCMS_SET_MIMO_PLCP_AMPDU(txh->FragPLCPFallback);
        }
-       /* endif (count) */
-       return err;
+
+       brcms_dbg_ht(wlc->hw->d11core, "wl%d: count %d ampdu_len %d\n",
+                    wlc->pub->unit, skb_queue_len(&session->skb_list),
+                    session->ampdu_len);
 }
 
 static void
@@ -909,7 +855,6 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
        u8 antselid = 0;
        u8 retry_limit, rr_retry_limit;
        struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(p);
-       struct wiphy *wiphy = wlc->wiphy;
 
 #ifdef DEBUG
        u8 hole[AMPDU_MAX_MPDU];
@@ -955,13 +900,14 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                if (supr_status) {
                        update_rate = false;
                        if (supr_status == TX_STATUS_SUPR_BADCH) {
-                               wiphy_err(wiphy,
+                               brcms_err(wlc->hw->d11core,
                                          "%s: Pkt tx suppressed, illegal channel possibly %d\n",
                                          __func__, CHSPEC_CHANNEL(
                                          wlc->default_bss->chanspec));
                        } else {
                                if (supr_status != TX_STATUS_SUPR_FRAG)
-                                       wiphy_err(wiphy, "%s: supr_status 0x%x\n",
+                                       brcms_err(wlc->hw->d11core,
+                                                 "%s: supr_status 0x%x\n",
                                                  __func__, supr_status);
                        }
                        /* no need to retry for badch; will fail again */
@@ -977,20 +923,14 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                                 * if there were underflows, but pre-loading
                                 * is not active, notify rate adaptation.
                                 */
-                               if (brcms_c_ffpld_check_txfunfl(wlc,
-                                       prio2fifo[tid]) > 0)
+                               if (brcms_c_ffpld_check_txfunfl(wlc, queue) > 0)
                                        tx_error = true;
                        }
                } else if (txs->phyerr) {
                        update_rate = false;
-                       wiphy_err(wiphy, "%s: ampdu tx phy error (0x%x)\n",
+                       brcms_err(wlc->hw->d11core,
+                                 "%s: ampdu tx phy error (0x%x)\n",
                                  __func__, txs->phyerr);
-
-                       if (brcm_msg_level & LOG_ERROR_VAL) {
-                               brcmu_prpkt("txpkt (AMPDU)", p);
-                               brcms_c_print_txdesc((struct d11txh *) p->data);
-                       }
-                       brcms_c_print_txstatus(txs);
                }
        }
 
@@ -1003,6 +943,8 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                h = (struct ieee80211_hdr *)(plcp + D11_PHY_HDR_LEN);
                seq = le16_to_cpu(h->seq_ctrl) >> SEQNUM_SHIFT;
 
+               trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, sizeof(*txh));
+
                if (tot_mpdu == 0) {
                        mcs = plcp[0] & MIMO_PLCP_MCS_MASK;
                        mimoantsel = le16_to_cpu(txh->ABI_MimoAntSel);
@@ -1012,10 +954,10 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                ack_recd = false;
                if (ba_recd) {
                        bindex = MODSUB_POW2(seq, start_seq, SEQNUM_MAX);
-                       BCMMSG(wiphy,
-                              "tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n",
-                              tid, seq, start_seq, bindex,
-                              isset(bitmap, bindex), index);
+                       brcms_dbg_ht(wlc->hw->d11core,
+                                    "tid %d seq %d, start_seq %d, bindex %d set %d, index %d\n",
+                                    tid, seq, start_seq, bindex,
+                                    isset(bitmap, bindex), index);
                        /* if acked then clear bit and free packet */
                        if ((bindex < AMPDU_TX_BA_MAX_WSIZE)
                            && isset(bitmap, bindex)) {
@@ -1046,14 +988,16 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                /* either retransmit or send bar if ack not recd */
                if (!ack_recd) {
                        if (retry && (ini->txretry[index] < (int)retry_limit)) {
+                               int ret;
                                ini->txretry[index]++;
                                ini->tx_in_transit--;
+                               ret = brcms_c_txfifo(wlc, queue, p);
                                /*
-                                * Use high prededence for retransmit to
-                                * give some punch
+                                * We shouldn't be out of space in the DMA
+                                * ring here since we're reinserting a frame
+                                * that was just pulled out.
                                 */
-                               brcms_c_txq_enq(wlc, scb, p,
-                                               BRCMS_PRIO_TO_HI_PREC(tid));
+                               WARN_ONCE(ret, "queue %d out of txds\n", queue);
                        } else {
                                /* Retry timeout */
                                ini->tx_in_transit--;
@@ -1064,9 +1008,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
                                    IEEE80211_TX_STAT_AMPDU_NO_BACK;
                                skb_pull(p, D11_PHY_HDR_LEN);
                                skb_pull(p, D11_TXH_LEN);
-                               BCMMSG(wiphy,
-                                      "BA Timeout, seq %d, in_transit %d\n",
-                                      seq, ini->tx_in_transit);
+                               brcms_dbg_ht(wlc->hw->d11core,
+                                            "BA Timeout, seq %d, in_transit %d\n",
+                                            seq, ini->tx_in_transit);
                                ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw,
                                                            p);
                        }
@@ -1080,12 +1024,9 @@ brcms_c_ampdu_dotxstatus_complete(struct ampdu_info *ampdu, struct scb *scb,
 
                p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
        }
-       brcms_c_send_q(wlc);
 
        /* update rate state */
        antselid = brcms_c_antsel_antsel2id(wlc->asi, mimoantsel);
-
-       brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
 }
 
 void
@@ -1133,6 +1074,8 @@ brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
                while (p) {
                        tx_info = IEEE80211_SKB_CB(p);
                        txh = (struct d11txh *) p->data;
+                       trace_brcms_txdesc(&wlc->hw->d11core->dev, txh,
+                                          sizeof(*txh));
                        mcl = le16_to_cpu(txh->MacTxControlLow);
                        brcmu_pkt_buf_free_skb(p);
                        /* break out if last packet of ampdu */
@@ -1142,7 +1085,6 @@ brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
                        p = dma_getnexttxp(wlc->hw->di[queue],
                                           DMA_RANGE_TRANSMITTED);
                }
-               brcms_c_txfifo_complete(wlc, queue, ampdu->txpkt_weight);
        }
 }
 
@@ -1181,23 +1123,6 @@ void brcms_c_ampdu_shm_upd(struct ampdu_info *ampdu)
        }
 }
 
-/*
- * callback function that helps flushing ampdu packets from a priority queue
- */
-static bool cb_del_ampdu_pkt(struct sk_buff *mpdu, void *arg_a)
-{
-       struct ieee80211_tx_info *tx_info = IEEE80211_SKB_CB(mpdu);
-       struct cb_del_ampdu_pars *ampdu_pars =
-                                (struct cb_del_ampdu_pars *)arg_a;
-       bool rc;
-
-       rc = tx_info->flags & IEEE80211_TX_CTL_AMPDU ? true : false;
-       rc = rc && (tx_info->rate_driver_data[0] == NULL || ampdu_pars->sta == NULL ||
-                   tx_info->rate_driver_data[0] == ampdu_pars->sta);
-       rc = rc && ((u8)(mpdu->priority) == ampdu_pars->tid);
-       return rc;
-}
-
 /*
  * callback function that helps invalidating ampdu packets in a DMA queue
  */
@@ -1218,15 +1143,5 @@ static void dma_cb_fn_ampdu(void *txi, void *arg_a)
 void brcms_c_ampdu_flush(struct brcms_c_info *wlc,
                     struct ieee80211_sta *sta, u16 tid)
 {
-       struct brcms_txq_info *qi = wlc->pkt_queue;
-       struct pktq *pq = &qi->q;
-       int prec;
-       struct cb_del_ampdu_pars ampdu_pars;
-
-       ampdu_pars.sta = sta;
-       ampdu_pars.tid = tid;
-       for (prec = 0; prec < pq->num_prec; prec++)
-               brcmu_pktq_pflush(pq, prec, true, cb_del_ampdu_pkt,
-                           (void *)&ampdu_pars);
        brcms_c_inval_dma_pkts(wlc->hw, sta, dma_cb_fn_ampdu);
 }
index 421f4ba7c63ccf67593248d3927e372b87f72e2e..73d01e5861090d99d875c886ae8783c9dff5561c 100644 (file)
 #ifndef _BRCM_AMPDU_H_
 #define _BRCM_AMPDU_H_
 
+/*
+ * Data structure representing an in-progress session for accumulating
+ * frames for AMPDU.
+ *
+ * wlc: pointer to common driver data
+ * skb_list: queue of skb's for AMPDU
+ * max_ampdu_len: maximum length for this AMPDU
+ * max_ampdu_frames: maximum number of frames for this AMPDU
+ * ampdu_len: total number of bytes accumulated for this AMPDU
+ * dma_len: DMA length of this AMPDU
+ */
+struct brcms_ampdu_session {
+       struct brcms_c_info *wlc;
+       struct sk_buff_head skb_list;
+       unsigned max_ampdu_len;
+       u16 max_ampdu_frames;
+       u16 ampdu_len;
+       u16 dma_len;
+};
+
+extern void brcms_c_ampdu_reset_session(struct brcms_ampdu_session *session,
+                                       struct brcms_c_info *wlc);
+extern int brcms_c_ampdu_add_frame(struct brcms_ampdu_session *session,
+                                  struct sk_buff *p);
+extern void brcms_c_ampdu_finalize(struct brcms_ampdu_session *session);
+
 extern struct ampdu_info *brcms_c_ampdu_attach(struct brcms_c_info *wlc);
 extern void brcms_c_ampdu_detach(struct ampdu_info *ampdu);
-extern int brcms_c_sendampdu(struct ampdu_info *ampdu,
-                            struct brcms_txq_info *qi,
-                            struct sk_buff **aggp, int prec);
 extern void brcms_c_ampdu_dotxstatus(struct ampdu_info *ampdu, struct scb *scb,
                                 struct sk_buff *p, struct tx_status *txs);
 extern void brcms_c_ampdu_macaddr_upd(struct brcms_c_info *wlc);
index 55e12c3279119facdcf3540fbb39773b47cc831f..54c616919590d2ebc89c5b15e3415c605104833f 100644 (file)
@@ -21,6 +21,7 @@
 #include "main.h"
 #include "phy_shim.h"
 #include "antsel.h"
+#include "debug.h"
 
 #define ANT_SELCFG_AUTO                0x80    /* bit indicates antenna sel AUTO */
 #define ANT_SELCFG_MASK                0x33    /* antenna configuration mask */
@@ -137,7 +138,8 @@ struct antsel_info *brcms_c_antsel_attach(struct brcms_c_info *wlc)
                                asi->antsel_avail = false;
                        } else {
                                asi->antsel_avail = false;
-                               wiphy_err(wlc->wiphy, "antsel_attach: 2o3 "
+                               brcms_err(wlc->hw->d11core,
+                                         "antsel_attach: 2o3 "
                                          "board cfg invalid\n");
                        }
 
index 27dd73eef56d6159a458939210df718176b7f359..871781e6a7138a0a9556c029dd8d265ecd53b733 100644 (file)
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#undef TRACE_SYSTEM
-#define TRACE_SYSTEM brcmsmac
-
 #if !defined(__TRACE_BRCMSMAC_H) || defined(TRACE_HEADER_MULTI_READ)
 
 #define __TRACE_BRCMSMAC_H
 
+#include <linux/types.h>
+#include <linux/device.h>
 #include <linux/tracepoint.h>
 #include "mac80211_if.h"
 
-#ifndef CONFIG_BRCMDBG
+#ifndef CONFIG_BRCM_TRACING
 #undef TRACE_EVENT
 #define TRACE_EVENT(name, proto, ...) \
 static inline void trace_ ## name(proto) {}
+#undef DECLARE_EVENT_CLASS
+#define DECLARE_EVENT_CLASS(...)
+#undef DEFINE_EVENT
+#define DEFINE_EVENT(evt_class, name, proto, ...) \
+static inline void trace_ ## name(proto) {}
 #endif
 
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM brcmsmac
+
 /*
  * We define a tracepoint, its arguments, its printk format and its
  * 'fast binary record' layout.
@@ -78,9 +85,165 @@ TRACE_EVENT(brcms_dpc,
        )
 );
 
+TRACE_EVENT(brcms_macintstatus,
+       TP_PROTO(const struct device *dev, int in_isr, u32 macintstatus,
+                u32 mask),
+       TP_ARGS(dev, in_isr, macintstatus, mask),
+       TP_STRUCT__entry(
+               __string(dev, dev_name(dev))
+               __field(int, in_isr)
+               __field(u32, macintstatus)
+               __field(u32, mask)
+       ),
+       TP_fast_assign(
+               __assign_str(dev, dev_name(dev));
+               __entry->in_isr = in_isr;
+               __entry->macintstatus = macintstatus;
+               __entry->mask = mask;
+       ),
+       TP_printk("[%s] in_isr=%d macintstatus=%#x mask=%#x", __get_str(dev),
+                 __entry->in_isr, __entry->macintstatus, __entry->mask)
+);
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM brcmsmac_tx
+
+TRACE_EVENT(brcms_txdesc,
+       TP_PROTO(const struct device *dev,
+                void *txh, size_t txh_len),
+       TP_ARGS(dev, txh, txh_len),
+       TP_STRUCT__entry(
+               __string(dev, dev_name(dev))
+               __dynamic_array(u8, txh, txh_len)
+       ),
+       TP_fast_assign(
+               __assign_str(dev, dev_name(dev));
+               memcpy(__get_dynamic_array(txh), txh, txh_len);
+       ),
+       TP_printk("[%s] txdesc", __get_str(dev))
+);
+
+TRACE_EVENT(brcms_txstatus,
+       TP_PROTO(const struct device *dev, u16 framelen, u16 frameid,
+                u16 status, u16 lasttxtime, u16 sequence, u16 phyerr,
+                u16 ackphyrxsh),
+       TP_ARGS(dev, framelen, frameid, status, lasttxtime, sequence, phyerr,
+               ackphyrxsh),
+       TP_STRUCT__entry(
+               __string(dev, dev_name(dev))
+               __field(u16, framelen)
+               __field(u16, frameid)
+               __field(u16, status)
+               __field(u16, lasttxtime)
+               __field(u16, sequence)
+               __field(u16, phyerr)
+               __field(u16, ackphyrxsh)
+       ),
+       TP_fast_assign(
+               __assign_str(dev, dev_name(dev));
+               __entry->framelen = framelen;
+               __entry->frameid = frameid;
+               __entry->status = status;
+               __entry->lasttxtime = lasttxtime;
+               __entry->sequence = sequence;
+               __entry->phyerr = phyerr;
+               __entry->ackphyrxsh = ackphyrxsh;
+       ),
+       TP_printk("[%s] FrameId %#04x TxStatus %#04x LastTxTime %#04x "
+                 "Seq %#04x PHYTxStatus %#04x RxAck %#04x",
+                 __get_str(dev), __entry->frameid, __entry->status,
+                 __entry->lasttxtime, __entry->sequence, __entry->phyerr,
+                 __entry->ackphyrxsh)
+);
+
+TRACE_EVENT(brcms_ampdu_session,
+       TP_PROTO(const struct device *dev, unsigned max_ampdu_len,
+                u16 max_ampdu_frames, u16 ampdu_len, u16 ampdu_frames,
+                u16 dma_len),
+       TP_ARGS(dev, max_ampdu_len, max_ampdu_frames, ampdu_len, ampdu_frames,
+               dma_len),
+       TP_STRUCT__entry(
+               __string(dev, dev_name(dev))
+               __field(unsigned, max_ampdu_len)
+               __field(u16, max_ampdu_frames)
+               __field(u16, ampdu_len)
+               __field(u16, ampdu_frames)
+               __field(u16, dma_len)
+       ),
+       TP_fast_assign(
+               __assign_str(dev, dev_name(dev));
+               __entry->max_ampdu_len = max_ampdu_len;
+               __entry->max_ampdu_frames = max_ampdu_frames;
+               __entry->ampdu_len = ampdu_len;
+               __entry->ampdu_frames = ampdu_frames;
+               __entry->dma_len = dma_len;
+       ),
+       TP_printk("[%s] ampdu session max_len=%u max_frames=%u len=%u frames=%u dma_len=%u",
+                 __get_str(dev), __entry->max_ampdu_len,
+                 __entry->max_ampdu_frames, __entry->ampdu_len,
+                 __entry->ampdu_frames, __entry->dma_len)
+);
+
+#undef TRACE_SYSTEM
+#define TRACE_SYSTEM brcmsmac_msg
+
+#define MAX_MSG_LEN    100
+
+DECLARE_EVENT_CLASS(brcms_msg_event,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf),
+       TP_STRUCT__entry(
+               __dynamic_array(char, msg, MAX_MSG_LEN)
+       ),
+       TP_fast_assign(
+               WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+                                      MAX_MSG_LEN, vaf->fmt,
+                                      *vaf->va) >= MAX_MSG_LEN);
+       ),
+       TP_printk("%s", __get_str(msg))
+);
+
+DEFINE_EVENT(brcms_msg_event, brcms_info,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(brcms_msg_event, brcms_warn,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(brcms_msg_event, brcms_err,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+DEFINE_EVENT(brcms_msg_event, brcms_crit,
+       TP_PROTO(struct va_format *vaf),
+       TP_ARGS(vaf)
+);
+
+TRACE_EVENT(brcms_dbg,
+       TP_PROTO(u32 level, const char *func, struct va_format *vaf),
+       TP_ARGS(level, func, vaf),
+       TP_STRUCT__entry(
+               __field(u32, level)
+               __string(func, func)
+               __dynamic_array(char, msg, MAX_MSG_LEN)
+       ),
+       TP_fast_assign(
+               __entry->level = level;
+               __assign_str(func, func);
+               WARN_ON_ONCE(vsnprintf(__get_dynamic_array(msg),
+                                      MAX_MSG_LEN, vaf->fmt,
+                                      *vaf->va) >= MAX_MSG_LEN);
+       ),
+       TP_printk("%s: %s", __get_str(func), __get_str(msg))
+);
+
 #endif /* __TRACE_BRCMSMAC_H */
 
-#ifdef CONFIG_BRCMDBG
+#ifdef CONFIG_BRCM_TRACING
 
 #undef TRACE_INCLUDE_PATH
 #define TRACE_INCLUDE_PATH .
@@ -89,4 +252,4 @@ TRACE_EVENT(brcms_dpc,
 
 #include <trace/define_trace.h>
 
-#endif /* CONFIG_BRCMDBG */
+#endif /* CONFIG_BRCM_TRACING */
index 64a48f06d68bfa124c1687bc1fa81a799fb5be82..a90b72202ec5a298b9cf6483cd5380ae5ef74ef0 100644 (file)
@@ -26,6 +26,7 @@
 #include "stf.h"
 #include "channel.h"
 #include "mac80211_if.h"
+#include "debug.h"
 
 /* QDB() macro takes a dB value and converts to a quarter dB value */
 #define QDB(n) ((n) * BRCMS_TXPWR_DB_FACTOR)
@@ -336,8 +337,6 @@ struct brcms_cm_info *brcms_c_channel_mgr_attach(struct brcms_c_info *wlc)
        const char *ccode = sprom->alpha2;
        int ccode_len = sizeof(sprom->alpha2);
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
-
        wlc_cm = kzalloc(sizeof(struct brcms_cm_info), GFP_ATOMIC);
        if (wlc_cm == NULL)
                return NULL;
@@ -615,8 +614,8 @@ brcms_c_valid_chanspec_ext(struct brcms_cm_info *wlc_cm, u16 chspec)
 
        /* check the chanspec */
        if (brcms_c_chspec_malformed(chspec)) {
-               wiphy_err(wlc->wiphy, "wl%d: malformed chanspec 0x%x\n",
-                       wlc->pub->unit, chspec);
+               brcms_err(wlc->hw->d11core, "wl%d: malformed chanspec 0x%x\n",
+                         wlc->pub->unit, chspec);
                return false;
        }
 
@@ -738,7 +737,8 @@ static int brcms_reg_notifier(struct wiphy *wiphy,
                mboolclr(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
        } else {
                mboolset(wlc->pub->radio_disabled, WL_RADIO_COUNTRY_DISABLE);
-               wiphy_err(wlc->wiphy, "wl%d: %s: no valid channel for \"%s\"\n",
+               brcms_err(wlc->hw->d11core,
+                         "wl%d: %s: no valid channel for \"%s\"\n",
                          wlc->pub->unit, __func__, request->alpha2);
        }
 
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.c b/drivers/net/wireless/brcm80211/brcmsmac/debug.c
new file mode 100644 (file)
index 0000000..6ba4136
--- /dev/null
@@ -0,0 +1,44 @@
+#include <linux/net.h>
+#include "types.h"
+#include "debug.h"
+#include "brcms_trace_events.h"
+
+#define __brcms_fn(fn)                                         \
+void __brcms_ ##fn(struct device *dev, const char *fmt, ...)   \
+{                                                              \
+       struct va_format vaf = {                                \
+               .fmt = fmt,                                     \
+       };                                                      \
+       va_list args;                                           \
+                                                               \
+       va_start(args, fmt);                                    \
+       vaf.va = &args;                                         \
+       dev_ ##fn(dev, "%pV", &vaf);                            \
+       trace_brcms_ ##fn(&vaf);                                \
+       va_end(args);                                           \
+}
+
+__brcms_fn(info)
+__brcms_fn(warn)
+__brcms_fn(err)
+__brcms_fn(crit)
+
+#if defined(CONFIG_BRCMDBG) || defined(CONFIG_BRCM_TRACING)
+void __brcms_dbg(struct device *dev, u32 level, const char *func,
+                const char *fmt, ...)
+{
+       struct va_format vaf = {
+               .fmt = fmt,
+       };
+       va_list args;
+
+       va_start(args, fmt);
+       vaf.va = &args;
+#ifdef CONFIG_BRCMDBG
+       if ((brcm_msg_level & level) && net_ratelimit())
+               dev_err(dev, "%s %pV", func, &vaf);
+#endif
+       trace_brcms_dbg(level, func, &vaf);
+       va_end(args);
+}
+#endif
diff --git a/drivers/net/wireless/brcm80211/brcmsmac/debug.h b/drivers/net/wireless/brcm80211/brcmsmac/debug.h
new file mode 100644 (file)
index 0000000..f77066b
--- /dev/null
@@ -0,0 +1,52 @@
+#ifndef _BRCMS_DEBUG_H_
+#define _BRCMS_DEBUG_H_
+
+#include <linux/device.h>
+#include <linux/bcma/bcma.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
+#include "main.h"
+#include "mac80211_if.h"
+
+__printf(2, 3)
+void __brcms_info(struct device *dev, const char *fmt, ...);
+__printf(2, 3)
+void __brcms_warn(struct device *dev, const char *fmt, ...);
+__printf(2, 3)
+void __brcms_err(struct device *dev, const char *fmt, ...);
+__printf(2, 3)
+void __brcms_crit(struct device *dev, const char *fmt, ...);
+
+#if defined(CONFIG_BRCMDBG) || defined(CONFIG_BRCM_TRACING)
+__printf(4, 5)
+void __brcms_dbg(struct device *dev, u32 level, const char *func,
+                const char *fmt, ...);
+#else
+static inline __printf(4, 5)
+void __brcms_dbg(struct device *dev, u32 level, const char *func,
+                const char *fmt, ...)
+{
+}
+#endif
+
+/*
+ * Debug macros cannot be used when wlc is uninitialized. Generally
+ * this means any code that could run before brcms_c_attach() has
+ * returned successfully probably shouldn't use the following macros.
+ */
+
+#define brcms_dbg(core, l, f, a...)    __brcms_dbg(&(core)->dev, l, __func__, f, ##a)
+#define brcms_info(core, f, a...)      __brcms_info(&(core)->dev, f, ##a)
+#define brcms_warn(core, f, a...)      __brcms_warn(&(core)->dev, f, ##a)
+#define brcms_err(core, f, a...)       __brcms_err(&(core)->dev, f, ##a)
+#define brcms_crit(core, f, a...)      __brcms_crit(&(core)->dev, f, ##a)
+
+#define brcms_dbg_info(core, f, a...)          brcms_dbg(core, BRCM_DL_INFO, f, ##a)
+#define brcms_dbg_mac80211(core, f, a...)      brcms_dbg(core, BRCM_DL_MAC80211, f, ##a)
+#define brcms_dbg_rx(core, f, a...)            brcms_dbg(core, BRCM_DL_RX, f, ##a)
+#define brcms_dbg_tx(core, f, a...)            brcms_dbg(core, BRCM_DL_TX, f, ##a)
+#define brcms_dbg_int(core, f, a...)           brcms_dbg(core, BRCM_DL_INT, f, ##a)
+#define brcms_dbg_dma(core, f, a...)           brcms_dbg(core, BRCM_DL_DMA, f, ##a)
+#define brcms_dbg_ht(core, f, a...)            brcms_dbg(core, BRCM_DL_HT, f, ##a)
+
+#endif /* _BRCMS_DEBUG_H_ */
index 5e53305bd9a9bc57901c1a0597b00de32208a57b..511e45775c333acdd8a94177695f5be034083c8c 100644 (file)
  * CONNECTION WITH THE USE OR PERFORMANCE OF THIS SOFTWARE.
  */
 
-#define pr_fmt(fmt) KBUILD_MODNAME ": " fmt
-
 #include <linux/slab.h>
 #include <linux/delay.h>
 #include <linux/pci.h>
+#include <net/cfg80211.h>
+#include <net/mac80211.h>
 
 #include <brcmu_utils.h>
 #include <aiutils.h>
 #include "types.h"
+#include "main.h"
 #include "dma.h"
 #include "soc.h"
+#include "scb.h"
+#include "ampdu.h"
+#include "debug.h"
+#include "brcms_trace_events.h"
 
 /*
  * dma register field offset calculation
 
 #define BCMEXTRAHDROOM 172
 
-/* debug/trace */
-#ifdef DEBUG
-#define        DMA_ERROR(fmt, ...)                                     \
-do {                                                           \
-       if (*di->msg_level & 1)                                 \
-               pr_debug("%s: " fmt, __func__, ##__VA_ARGS__);  \
-} while (0)
-#define        DMA_TRACE(fmt, ...)                                     \
-do {                                                           \
-       if (*di->msg_level & 2)                                 \
-               pr_debug("%s: " fmt, __func__, ##__VA_ARGS__);  \
-} while (0)
-#else
-#define        DMA_ERROR(fmt, ...)                     \
-       no_printk(fmt, ##__VA_ARGS__)
-#define        DMA_TRACE(fmt, ...)                     \
-       no_printk(fmt, ##__VA_ARGS__)
-#endif                         /* DEBUG */
-
-#define        DMA_NONE(fmt, ...)                      \
-       no_printk(fmt, ##__VA_ARGS__)
-
 #define        MAXNAMEL        8       /* 8 char names */
 
 /* macros to convert between byte offsets and indexes */
@@ -224,12 +207,14 @@ struct dma64desc {
 /* dma engine software state */
 struct dma_info {
        struct dma_pub dma; /* exported structure */
-       uint *msg_level;        /* message level pointer */
        char name[MAXNAMEL];    /* callers name for diag msgs */
 
        struct bcma_device *core;
        struct device *dmadev;
 
+       /* session information for AMPDU */
+       struct brcms_ampdu_session ampdu_session;
+
        bool dma64;     /* this dma engine is operating in 64-bit mode */
        bool addrext;   /* this dma engine supports DmaExtendedAddrChanges */
 
@@ -298,12 +283,6 @@ struct dma_info {
        bool aligndesc_4k;
 };
 
-/*
- * default dma message level (if input msg_level
- * pointer is null in dma_attach())
- */
-static uint dma_msg_level;
-
 /* Check for odd number of 1's */
 static u32 parity32(__le32 data)
 {
@@ -353,7 +332,7 @@ static uint prevtxd(struct dma_info *di, uint i)
 
 static uint nextrxd(struct dma_info *di, uint i)
 {
-       return txd(di, i + 1);
+       return rxd(di, i + 1);
 }
 
 static uint ntxdactive(struct dma_info *di, uint h, uint t)
@@ -371,7 +350,7 @@ static uint _dma_ctrlflags(struct dma_info *di, uint mask, uint flags)
        uint dmactrlflags;
 
        if (di == NULL) {
-               DMA_ERROR("NULL dma handle\n");
+               brcms_dbg_dma(di->core, "NULL dma handle\n");
                return 0;
        }
 
@@ -423,13 +402,15 @@ static bool _dma_isaddrext(struct dma_info *di)
        /* not all tx or rx channel are available */
        if (di->d64txregbase != 0) {
                if (!_dma64_addrext(di, DMA64TXREGOFFS(di, control)))
-                       DMA_ERROR("%s: DMA64 tx doesn't have AE set\n",
-                                 di->name);
+                       brcms_dbg_dma(di->core,
+                                     "%s: DMA64 tx doesn't have AE set\n",
+                                     di->name);
                return true;
        } else if (di->d64rxregbase != 0) {
                if (!_dma64_addrext(di, DMA64RXREGOFFS(di, control)))
-                       DMA_ERROR("%s: DMA64 rx doesn't have AE set\n",
-                                 di->name);
+                       brcms_dbg_dma(di->core,
+                                     "%s: DMA64 rx doesn't have AE set\n",
+                                     di->name);
                return true;
        }
 
@@ -530,8 +511,9 @@ static bool dma64_alloc(struct dma_info *di, uint direction)
                va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
                        &alloced, &di->txdpaorig);
                if (va == NULL) {
-                       DMA_ERROR("%s: DMA_ALLOC_CONSISTENT(ntxd) failed\n",
-                                 di->name);
+                       brcms_dbg_dma(di->core,
+                                     "%s: DMA_ALLOC_CONSISTENT(ntxd) failed\n",
+                                     di->name);
                        return false;
                }
                align = (1 << align_bits);
@@ -544,8 +526,9 @@ static bool dma64_alloc(struct dma_info *di, uint direction)
                va = dma_ringalloc(di, D64RINGALIGN, size, &align_bits,
                        &alloced, &di->rxdpaorig);
                if (va == NULL) {
-                       DMA_ERROR("%s: DMA_ALLOC_CONSISTENT(nrxd) failed\n",
-                                 di->name);
+                       brcms_dbg_dma(di->core,
+                                     "%s: DMA_ALLOC_CONSISTENT(nrxd) failed\n",
+                                     di->name);
                        return false;
                }
                align = (1 << align_bits);
@@ -564,12 +547,13 @@ static bool _dma_alloc(struct dma_info *di, uint direction)
        return dma64_alloc(di, direction);
 }
 
-struct dma_pub *dma_attach(char *name, struct si_pub *sih,
-                          struct bcma_device *core,
+struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc,
                           uint txregbase, uint rxregbase, uint ntxd, uint nrxd,
                           uint rxbufsize, int rxextheadroom,
-                          uint nrxpost, uint rxoffset, uint *msg_level)
+                          uint nrxpost, uint rxoffset)
 {
+       struct si_pub *sih = wlc->hw->sih;
+       struct bcma_device *core = wlc->hw->d11core;
        struct dma_info *di;
        u8 rev = core->id.rev;
        uint size;
@@ -580,9 +564,6 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
        if (di == NULL)
                return NULL;
 
-       di->msg_level = msg_level ? msg_level : &dma_msg_level;
-
-
        di->dma64 =
                ((bcma_aread32(core, BCMA_IOST) & SISF_DMA64) == SISF_DMA64);
 
@@ -598,11 +579,11 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
         */
        _dma_ctrlflags(di, DMA_CTRL_ROC | DMA_CTRL_PEN, 0);
 
-       DMA_TRACE("%s: %s flags 0x%x ntxd %d nrxd %d "
-                 "rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d "
-                 "txregbase %u rxregbase %u\n", name, "DMA64",
-                 di->dma.dmactrlflags, ntxd, nrxd, rxbufsize,
-                 rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase);
+       brcms_dbg_dma(di->core, "%s: %s flags 0x%x ntxd %d nrxd %d "
+                     "rxbufsize %d rxextheadroom %d nrxpost %d rxoffset %d "
+                     "txregbase %u rxregbase %u\n", name, "DMA64",
+                     di->dma.dmactrlflags, ntxd, nrxd, rxbufsize,
+                     rxextheadroom, nrxpost, rxoffset, txregbase, rxregbase);
 
        /* make a private copy of our callers name */
        strncpy(di->name, name, MAXNAMEL);
@@ -664,8 +645,8 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
                di->dmadesc_align = 4;  /* 16 byte alignment */
        }
 
-       DMA_NONE("DMA descriptor align_needed %d, align %d\n",
-                di->aligndesc_4k, di->dmadesc_align);
+       brcms_dbg_dma(di->core, "DMA descriptor align_needed %d, align %d\n",
+                     di->aligndesc_4k, di->dmadesc_align);
 
        /* allocate tx packet pointer vector */
        if (ntxd) {
@@ -703,21 +684,27 @@ struct dma_pub *dma_attach(char *name, struct si_pub *sih,
 
        if ((di->ddoffsetlow != 0) && !di->addrext) {
                if (di->txdpa > SI_PCI_DMA_SZ) {
-                       DMA_ERROR("%s: txdpa 0x%x: addrext not supported\n",
-                                 di->name, (u32)di->txdpa);
+                       brcms_dbg_dma(di->core,
+                                     "%s: txdpa 0x%x: addrext not supported\n",
+                                     di->name, (u32)di->txdpa);
                        goto fail;
                }
                if (di->rxdpa > SI_PCI_DMA_SZ) {
-                       DMA_ERROR("%s: rxdpa 0x%x: addrext not supported\n",
-                                 di->name, (u32)di->rxdpa);
+                       brcms_dbg_dma(di->core,
+                                     "%s: rxdpa 0x%x: addrext not supported\n",
+                                     di->name, (u32)di->rxdpa);
                        goto fail;
                }
        }
 
-       DMA_TRACE("ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh 0x%x addrext %d\n",
-                 di->ddoffsetlow, di->ddoffsethigh,
-                 di->dataoffsetlow, di->dataoffsethigh,
-                 di->addrext);
+       /* Initialize AMPDU session */
+       brcms_c_ampdu_reset_session(&di->ampdu_session, wlc);
+
+       brcms_dbg_dma(di->core,
+                     "ddoffsetlow 0x%x ddoffsethigh 0x%x dataoffsetlow 0x%x dataoffsethigh 0x%x addrext %d\n",
+                     di->ddoffsetlow, di->ddoffsethigh,
+                     di->dataoffsetlow, di->dataoffsethigh,
+                     di->addrext);
 
        return (struct dma_pub *) di;
 
@@ -763,7 +750,7 @@ void dma_detach(struct dma_pub *pub)
 {
        struct dma_info *di = (struct dma_info *)pub;
 
-       DMA_TRACE("%s:\n", di->name);
+       brcms_dbg_dma(di->core, "%s:\n", di->name);
 
        /* free dma descriptor rings */
        if (di->txd64)
@@ -839,7 +826,7 @@ static void _dma_rxenable(struct dma_info *di)
        uint dmactrlflags = di->dma.dmactrlflags;
        u32 control;
 
-       DMA_TRACE("%s:\n", di->name);
+       brcms_dbg_dma(di->core, "%s:\n", di->name);
 
        control = D64_RC_RE | (bcma_read32(di->core,
                                           DMA64RXREGOFFS(di, control)) &
@@ -859,7 +846,7 @@ void dma_rxinit(struct dma_pub *pub)
 {
        struct dma_info *di = (struct dma_info *)pub;
 
-       DMA_TRACE("%s:\n", di->name);
+       brcms_dbg_dma(di->core, "%s:\n", di->name);
 
        if (di->nrxd == 0)
                return;
@@ -954,7 +941,7 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
                return 0;
 
        len = le16_to_cpu(*(__le16 *) (p->data));
-       DMA_TRACE("%s: dma_rx len %d\n", di->name, len);
+       brcms_dbg_dma(di->core, "%s: dma_rx len %d\n", di->name, len);
        dma_spin_for_len(len, p);
 
        /* set actual length */
@@ -981,14 +968,15 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
                                              DMA64RXREGOFFS(di, status0)) &
                                  D64_RS0_CD_MASK) - di->rcvptrbase) &
                                D64_RS0_CD_MASK, struct dma64desc);
-                       DMA_ERROR("rxin %d rxout %d, hw_curr %d\n",
-                                  di->rxin, di->rxout, cur);
+                       brcms_dbg_dma(di->core,
+                                     "rxin %d rxout %d, hw_curr %d\n",
+                                     di->rxin, di->rxout, cur);
                }
 #endif                         /* DEBUG */
 
                if ((di->dma.dmactrlflags & DMA_CTRL_RXMULTI) == 0) {
-                       DMA_ERROR("%s: bad frame length (%d)\n",
-                                 di->name, len);
+                       brcms_dbg_dma(di->core, "%s: bad frame length (%d)\n",
+                                     di->name, len);
                        skb_queue_walk_safe(&dma_frames, p, next) {
                                skb_unlink(p, &dma_frames);
                                brcmu_pkt_buf_free_skb(p);
@@ -1005,7 +993,7 @@ int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list)
 
 static bool dma64_rxidle(struct dma_info *di)
 {
-       DMA_TRACE("%s:\n", di->name);
+       brcms_dbg_dma(di->core, "%s:\n", di->name);
 
        if (di->nrxd == 0)
                return true;
@@ -1016,6 +1004,17 @@ static bool dma64_rxidle(struct dma_info *di)
                 D64_RS0_CD_MASK));
 }
 
+static bool dma64_txidle(struct dma_info *di)
+{
+       if (di->ntxd == 0)
+               return true;
+
+       return ((bcma_read32(di->core,
+                            DMA64TXREGOFFS(di, status0)) & D64_XS0_CD_MASK) ==
+               (bcma_read32(di->core, DMA64TXREGOFFS(di, ptr)) &
+                D64_XS0_CD_MASK));
+}
+
 /*
  * post receive buffers
  *  return false is refill failed completely and ring is empty this will stall
@@ -1047,7 +1046,7 @@ bool dma_rxfill(struct dma_pub *pub)
 
        n = di->nrxpost - nrxdactive(di, rxin, rxout);
 
-       DMA_TRACE("%s: post %d\n", di->name, n);
+       brcms_dbg_dma(di->core, "%s: post %d\n", di->name, n);
 
        if (di->rxbufsize > BCMEXTRAHDROOM)
                extra_offset = di->rxextrahdrroom;
@@ -1060,9 +1059,11 @@ bool dma_rxfill(struct dma_pub *pub)
                p = brcmu_pkt_buf_get_skb(di->rxbufsize + extra_offset);
 
                if (p == NULL) {
-                       DMA_ERROR("%s: out of rxbufs\n", di->name);
+                       brcms_dbg_dma(di->core, "%s: out of rxbufs\n",
+                                     di->name);
                        if (i == 0 && dma64_rxidle(di)) {
-                               DMA_ERROR("%s: ring is empty !\n", di->name);
+                               brcms_dbg_dma(di->core, "%s: ring is empty !\n",
+                                             di->name);
                                ring_empty = true;
                        }
                        di->dma.rxnobuf++;
@@ -1107,7 +1108,7 @@ void dma_rxreclaim(struct dma_pub *pub)
        struct dma_info *di = (struct dma_info *)pub;
        struct sk_buff *p;
 
-       DMA_TRACE("%s:\n", di->name);
+       brcms_dbg_dma(di->core, "%s:\n", di->name);
 
        while ((p = _dma_getnextrxp(di, true)))
                brcmu_pkt_buf_free_skb(p);
@@ -1138,7 +1139,7 @@ void dma_txinit(struct dma_pub *pub)
        struct dma_info *di = (struct dma_info *)pub;
        u32 control = D64_XC_XE;
 
-       DMA_TRACE("%s:\n", di->name);
+       brcms_dbg_dma(di->core, "%s:\n", di->name);
 
        if (di->ntxd == 0)
                return;
@@ -1170,7 +1171,7 @@ void dma_txsuspend(struct dma_pub *pub)
 {
        struct dma_info *di = (struct dma_info *)pub;
 
-       DMA_TRACE("%s:\n", di->name);
+       brcms_dbg_dma(di->core, "%s:\n", di->name);
 
        if (di->ntxd == 0)
                return;
@@ -1182,7 +1183,7 @@ void dma_txresume(struct dma_pub *pub)
 {
        struct dma_info *di = (struct dma_info *)pub;
 
-       DMA_TRACE("%s:\n", di->name);
+       brcms_dbg_dma(di->core, "%s:\n", di->name);
 
        if (di->ntxd == 0)
                return;
@@ -1205,11 +1206,11 @@ void dma_txreclaim(struct dma_pub *pub, enum txd_range range)
        struct dma_info *di = (struct dma_info *)pub;
        struct sk_buff *p;
 
-       DMA_TRACE("%s: %s\n",
-                 di->name,
-                 range == DMA_RANGE_ALL ? "all" :
-                 range == DMA_RANGE_TRANSMITTED ? "transmitted" :
-                 "transferred");
+       brcms_dbg_dma(di->core, "%s: %s\n",
+                     di->name,
+                     range == DMA_RANGE_ALL ? "all" :
+                     range == DMA_RANGE_TRANSMITTED ? "transmitted" :
+                     "transferred");
 
        if (di->txin == di->txout)
                return;
@@ -1264,39 +1265,25 @@ bool dma_rxreset(struct dma_pub *pub)
        return status == D64_RS0_RS_DISABLED;
 }
 
-/*
- * !! tx entry routine
- * WARNING: call must check the return value for error.
- *   the error(toss frames) could be fatal and cause many subsequent hard
- *   to debug problems
- */
-int dma_txfast(struct dma_pub *pub, struct sk_buff *p, bool commit)
+static void dma_txenq(struct dma_info *di, struct sk_buff *p)
 {
-       struct dma_info *di = (struct dma_info *)pub;
        unsigned char *data;
        uint len;
        u16 txout;
        u32 flags = 0;
        dma_addr_t pa;
 
-       DMA_TRACE("%s:\n", di->name);
-
        txout = di->txout;
 
+       if (WARN_ON(nexttxd(di, txout) == di->txin))
+               return;
+
        /*
         * obtain and initialize transmit descriptor entry.
         */
        data = p->data;
        len = p->len;
 
-       /* no use to transmit a zero length packet */
-       if (len == 0)
-               return 0;
-
-       /* return nonzero if out of tx descriptors */
-       if (nexttxd(di, txout) == di->txin)
-               goto outoftxd;
-
        /* get physical address of buffer start */
        pa = dma_map_single(di->dmadev, data, len, DMA_TO_DEVICE);
 
@@ -1318,23 +1305,147 @@ int dma_txfast(struct dma_pub *pub, struct sk_buff *p, bool commit)
 
        /* bump the tx descriptor index */
        di->txout = txout;
+}
 
-       /* kick the chip */
-       if (commit)
-               bcma_write32(di->core, DMA64TXREGOFFS(di, ptr),
-                     di->xmtptrbase + I2B(txout, struct dma64desc));
+static void ampdu_finalize(struct dma_info *di)
+{
+       struct brcms_ampdu_session *session = &di->ampdu_session;
+       struct sk_buff *p;
+
+       trace_brcms_ampdu_session(&session->wlc->hw->d11core->dev,
+                                 session->max_ampdu_len,
+                                 session->max_ampdu_frames,
+                                 session->ampdu_len,
+                                 skb_queue_len(&session->skb_list),
+                                 session->dma_len);
+
+       if (WARN_ON(skb_queue_empty(&session->skb_list)))
+               return;
+
+       brcms_c_ampdu_finalize(session);
+
+       while (!skb_queue_empty(&session->skb_list)) {
+               p = skb_dequeue(&session->skb_list);
+               dma_txenq(di, p);
+       }
+
+       bcma_write32(di->core, DMA64TXREGOFFS(di, ptr),
+                    di->xmtptrbase + I2B(di->txout, struct dma64desc));
+       brcms_c_ampdu_reset_session(session, session->wlc);
+}
+
+static void prep_ampdu_frame(struct dma_info *di, struct sk_buff *p)
+{
+       struct brcms_ampdu_session *session = &di->ampdu_session;
+       int ret;
+
+       ret = brcms_c_ampdu_add_frame(session, p);
+       if (ret == -ENOSPC) {
+               /*
+                * AMPDU cannot accomodate this frame. Close out the in-
+                * progress AMPDU session and start a new one.
+                */
+               ampdu_finalize(di);
+               ret = brcms_c_ampdu_add_frame(session, p);
+       }
+
+       WARN_ON(ret);
+}
+
+/* Update count of available tx descriptors based on current DMA state */
+static void dma_update_txavail(struct dma_info *di)
+{
+       /*
+        * Available space is number of descriptors less the number of
+        * active descriptors and the number of queued AMPDU frames.
+        */
+       di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) -
+                         skb_queue_len(&di->ampdu_session.skb_list) - 1;
+}
+
+/*
+ * !! tx entry routine
+ * WARNING: call must check the return value for error.
+ *   the error(toss frames) could be fatal and cause many subsequent hard
+ *   to debug problems
+ */
+int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
+              struct sk_buff *p)
+{
+       struct dma_info *di = (struct dma_info *)pub;
+       struct brcms_ampdu_session *session = &di->ampdu_session;
+       struct ieee80211_tx_info *tx_info;
+       bool is_ampdu;
+
+       /* no use to transmit a zero length packet */
+       if (p->len == 0)
+               return 0;
+
+       /* return nonzero if out of tx descriptors */
+       if (di->dma.txavail == 0 || nexttxd(di, di->txout) == di->txin)
+               goto outoftxd;
+
+       tx_info = IEEE80211_SKB_CB(p);
+       is_ampdu = tx_info->flags & IEEE80211_TX_CTL_AMPDU;
+       if (is_ampdu)
+               prep_ampdu_frame(di, p);
+       else
+               dma_txenq(di, p);
 
        /* tx flow control */
-       di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;
+       dma_update_txavail(di);
+
+       /* kick the chip */
+       if (is_ampdu) {
+               /*
+                * Start sending data if we've got a full AMPDU, there's
+                * no more space in the DMA ring, or the ring isn't
+                * currently transmitting.
+                */
+               if (skb_queue_len(&session->skb_list) == session->max_ampdu_frames ||
+                   di->dma.txavail == 0 || dma64_txidle(di))
+                       ampdu_finalize(di);
+       } else {
+               bcma_write32(di->core, DMA64TXREGOFFS(di, ptr),
+                            di->xmtptrbase + I2B(di->txout, struct dma64desc));
+       }
 
        return 0;
 
  outoftxd:
-       DMA_ERROR("%s: out of txds !!!\n", di->name);
+       brcms_dbg_dma(di->core, "%s: out of txds !!!\n", di->name);
        brcmu_pkt_buf_free_skb(p);
        di->dma.txavail = 0;
        di->dma.txnobuf++;
-       return -1;
+       return -ENOSPC;
+}
+
+void dma_txflush(struct dma_pub *pub)
+{
+       struct dma_info *di = (struct dma_info *)pub;
+       struct brcms_ampdu_session *session = &di->ampdu_session;
+
+       if (!skb_queue_empty(&session->skb_list))
+               ampdu_finalize(di);
+}
+
+int dma_txpending(struct dma_pub *pub)
+{
+       struct dma_info *di = (struct dma_info *)pub;
+       return ntxdactive(di, di->txin, di->txout);
+}
+
+/*
+ * If we have an active AMPDU session and are not transmitting,
+ * this function will force tx to start.
+ */
+void dma_kick_tx(struct dma_pub *pub)
+{
+       struct dma_info *di = (struct dma_info *)pub;
+       struct brcms_ampdu_session *session = &di->ampdu_session;
+
+       if (!skb_queue_empty(&session->skb_list) && dma64_txidle(di))
+               ampdu_finalize(di);
 }
 
 /*
@@ -1354,11 +1465,11 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
        u16 active_desc;
        struct sk_buff *txp;
 
-       DMA_TRACE("%s: %s\n",
-                 di->name,
-                 range == DMA_RANGE_ALL ? "all" :
-                 range == DMA_RANGE_TRANSMITTED ? "transmitted" :
-                 "transferred");
+       brcms_dbg_dma(di->core, "%s: %s\n",
+                     di->name,
+                     range == DMA_RANGE_ALL ? "all" :
+                     range == DMA_RANGE_TRANSMITTED ? "transmitted" :
+                     "transferred");
 
        if (di->ntxd == 0)
                return NULL;
@@ -1412,13 +1523,13 @@ struct sk_buff *dma_getnexttxp(struct dma_pub *pub, enum txd_range range)
        di->txin = i;
 
        /* tx flow control */
-       di->dma.txavail = di->ntxd - ntxdactive(di, di->txin, di->txout) - 1;
+       dma_update_txavail(di);
 
        return txp;
 
  bogus:
-       DMA_NONE("bogus curr: start %d end %d txout %d\n",
-                start, end, di->txout);
+       brcms_dbg_dma(di->core, "bogus curr: start %d end %d txout %d\n",
+                     start, end, di->txout);
        return NULL;
 }
 
index cc269ee5c49995f89d5c5c9a9d0183693935f2f7..ff5b80b0904636661ced2b2896c7730312a734bd 100644 (file)
@@ -74,12 +74,11 @@ struct dma_pub {
        uint txnobuf;           /* tx out of dma descriptors */
 };
 
-extern struct dma_pub *dma_attach(char *name, struct si_pub *sih,
-                                 struct bcma_device *d11core,
+extern struct dma_pub *dma_attach(char *name, struct brcms_c_info *wlc,
                                  uint txregbase, uint rxregbase,
                                  uint ntxd, uint nrxd,
                                  uint rxbufsize, int rxextheadroom,
-                                 uint nrxpost, uint rxoffset, uint *msg_level);
+                                 uint nrxpost, uint rxoffset);
 
 void dma_rxinit(struct dma_pub *pub);
 int dma_rx(struct dma_pub *pub, struct sk_buff_head *skb_list);
@@ -87,7 +86,11 @@ bool dma_rxfill(struct dma_pub *pub);
 bool dma_rxreset(struct dma_pub *pub);
 bool dma_txreset(struct dma_pub *pub);
 void dma_txinit(struct dma_pub *pub);
-int dma_txfast(struct dma_pub *pub, struct sk_buff *p0, bool commit);
+int dma_txfast(struct brcms_c_info *wlc, struct dma_pub *pub,
+              struct sk_buff *p0);
+void dma_txflush(struct dma_pub *pub);
+int dma_txpending(struct dma_pub *pub);
+void dma_kick_tx(struct dma_pub *pub);
 void dma_txsuspend(struct dma_pub *pub);
 bool dma_txsuspended(struct dma_pub *pub);
 void dma_txresume(struct dma_pub *pub);
index a744ea5a95599797023a0040401ab1816855f77f..1710ccba8bacf2c49961be0a61d89f6332cfbed4 100644 (file)
@@ -33,6 +33,7 @@
 #include "ucode_loader.h"
 #include "mac80211_if.h"
 #include "main.h"
+#include "debug.h"
 
 #define N_TX_QUEUES    4 /* #tx queues on mac80211<->driver interface */
 
@@ -98,10 +99,14 @@ static struct bcma_device_id brcms_coreid_table[] = {
 };
 MODULE_DEVICE_TABLE(bcma, brcms_coreid_table);
 
-#ifdef DEBUG
-static int msglevel = 0xdeadbeef;
-module_param(msglevel, int, 0);
-#endif                         /* DEBUG */
+#if defined(CONFIG_BRCMDBG)
+/*
+ * Module parameter for setting the debug message level. Available
+ * flags are specified by the BRCM_DL_* macros in
+ * drivers/net/wireless/brcm80211/include/defs.h.
+ */
+module_param_named(debug, brcm_msg_level, uint, S_IRUGO | S_IWUSR);
+#endif
 
 static struct ieee80211_channel brcms_2ghz_chantable[] = {
        CHAN2GHZ(1, 2412, IEEE80211_CHAN_NO_HT40MINUS),
@@ -276,7 +281,7 @@ static void brcms_ops_tx(struct ieee80211_hw *hw,
 
        spin_lock_bh(&wl->lock);
        if (!wl->pub->up) {
-               wiphy_err(wl->wiphy, "ops->tx called while down\n");
+               brcms_err(wl->wlc->hw->d11core, "ops->tx called while down\n");
                kfree_skb(skb);
                goto done;
        }
@@ -313,8 +318,8 @@ static int brcms_ops_start(struct ieee80211_hw *hw)
        spin_unlock_bh(&wl->lock);
 
        if (err != 0)
-               wiphy_err(hw->wiphy, "%s: brcms_up() returned %d\n", __func__,
-                         err);
+               brcms_err(wl->wlc->hw->d11core, "%s: brcms_up() returned %d\n",
+                         __func__, err);
        return err;
 }
 
@@ -332,7 +337,7 @@ static void brcms_ops_stop(struct ieee80211_hw *hw)
        status = brcms_c_chipmatch(wl->wlc->hw->d11core);
        spin_unlock_bh(&wl->lock);
        if (!status) {
-               wiphy_err(wl->wiphy,
+               brcms_err(wl->wlc->hw->d11core,
                          "wl: brcms_ops_stop: chipmatch failed\n");
                return;
        }
@@ -350,8 +355,9 @@ brcms_ops_add_interface(struct ieee80211_hw *hw, struct ieee80211_vif *vif)
 
        /* Just STA for now */
        if (vif->type != NL80211_IFTYPE_STATION) {
-               wiphy_err(hw->wiphy, "%s: Attempt to add type %d, only"
-                         " STA for now\n", __func__, vif->type);
+               brcms_err(wl->wlc->hw->d11core,
+                         "%s: Attempt to add type %d, only STA for now\n",
+                         __func__, vif->type);
                return -EOPNOTSUPP;
        }
 
@@ -370,9 +376,9 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
 {
        struct ieee80211_conf *conf = &hw->conf;
        struct brcms_info *wl = hw->priv;
+       struct bcma_device *core = wl->wlc->hw->d11core;
        int err = 0;
        int new_int;
-       struct wiphy *wiphy = hw->wiphy;
 
        spin_lock_bh(&wl->lock);
        if (changed & IEEE80211_CONF_CHANGE_LISTEN_INTERVAL) {
@@ -380,25 +386,26 @@ static int brcms_ops_config(struct ieee80211_hw *hw, u32 changed)
                                                   conf->listen_interval);
        }
        if (changed & IEEE80211_CONF_CHANGE_MONITOR)
-               wiphy_dbg(wiphy, "%s: change monitor mode: %s\n",
-                         __func__, conf->flags & IEEE80211_CONF_MONITOR ?
-                         "true" : "false");
+               brcms_dbg_info(core, "%s: change monitor mode: %s\n",
+                              __func__, conf->flags & IEEE80211_CONF_MONITOR ?
+                              "true" : "false");
        if (changed & IEEE80211_CONF_CHANGE_PS)
-               wiphy_err(wiphy, "%s: change power-save mode: %s (implement)\n",
+               brcms_err(core, "%s: change power-save mode: %s (implement)\n",
                          __func__, conf->flags & IEEE80211_CONF_PS ?
                          "true" : "false");
 
        if (changed & IEEE80211_CONF_CHANGE_POWER) {
                err = brcms_c_set_tx_power(wl->wlc, conf->power_level);
                if (err < 0) {
-                       wiphy_err(wiphy, "%s: Error setting power_level\n",
+                       brcms_err(core, "%s: Error setting power_level\n",
                                  __func__);
                        goto config_out;
                }
                new_int = brcms_c_get_tx_power(wl->wlc);
                if (new_int != conf->power_level)
-                       wiphy_err(wiphy, "%s: Power level req != actual, %d %d"
-                                 "\n", __func__, conf->power_level,
+                       brcms_err(core,
+                                 "%s: Power level req != actual, %d %d\n",
+                                 __func__, conf->power_level,
                                  new_int);
        }
        if (changed & IEEE80211_CONF_CHANGE_CHANNEL) {
@@ -425,13 +432,13 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
                        struct ieee80211_bss_conf *info, u32 changed)
 {
        struct brcms_info *wl = hw->priv;
-       struct wiphy *wiphy = hw->wiphy;
+       struct bcma_device *core = wl->wlc->hw->d11core;
 
        if (changed & BSS_CHANGED_ASSOC) {
                /* association status changed (associated/disassociated)
                 * also implies a change in the AID.
                 */
-               wiphy_err(wiphy, "%s: %s: %sassociated\n", KBUILD_MODNAME,
+               brcms_err(core, "%s: %s: %sassociated\n", KBUILD_MODNAME,
                          __func__, info->assoc ? "" : "dis");
                spin_lock_bh(&wl->lock);
                brcms_c_associate_upd(wl->wlc, info->assoc);
@@ -491,7 +498,7 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
                error = brcms_c_set_rateset(wl->wlc, &rs);
                spin_unlock_bh(&wl->lock);
                if (error)
-                       wiphy_err(wiphy, "changing basic rates failed: %d\n",
+                       brcms_err(core, "changing basic rates failed: %d\n",
                                  error);
        }
        if (changed & BSS_CHANGED_BEACON_INT) {
@@ -508,30 +515,30 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
        }
        if (changed & BSS_CHANGED_BEACON)
                /* Beacon data changed, retrieve new beacon (beaconing modes) */
-               wiphy_err(wiphy, "%s: beacon changed\n", __func__);
+               brcms_err(core, "%s: beacon changed\n", __func__);
 
        if (changed & BSS_CHANGED_BEACON_ENABLED) {
                /* Beaconing should be enabled/disabled (beaconing modes) */
-               wiphy_err(wiphy, "%s: Beacon enabled: %s\n", __func__,
+               brcms_err(core, "%s: Beacon enabled: %s\n", __func__,
                          info->enable_beacon ? "true" : "false");
        }
 
        if (changed & BSS_CHANGED_CQM) {
                /* Connection quality monitor config changed */
-               wiphy_err(wiphy, "%s: cqm change: threshold %d, hys %d "
+               brcms_err(core, "%s: cqm change: threshold %d, hys %d "
                          " (implement)\n", __func__, info->cqm_rssi_thold,
                          info->cqm_rssi_hyst);
        }
 
        if (changed & BSS_CHANGED_IBSS) {
                /* IBSS join status changed */
-               wiphy_err(wiphy, "%s: IBSS joined: %s (implement)\n", __func__,
-                         info->ibss_joined ? "true" : "false");
+               brcms_err(core, "%s: IBSS joined: %s (implement)\n",
+                         __func__, info->ibss_joined ? "true" : "false");
        }
 
        if (changed & BSS_CHANGED_ARP_FILTER) {
                /* Hardware ARP filter address list or state changed */
-               wiphy_err(wiphy, "%s: arp filtering: enabled %s, count %d"
+               brcms_err(core, "%s: arp filtering: enabled %s, count %d"
                          " (implement)\n", __func__, info->arp_filter_enabled ?
                          "true" : "false", info->arp_addr_cnt);
        }
@@ -541,8 +548,8 @@ brcms_ops_bss_info_changed(struct ieee80211_hw *hw,
                 * QoS for this association was enabled/disabled.
                 * Note that it is only ever disabled for station mode.
                 */
-               wiphy_err(wiphy, "%s: qos enabled: %s (implement)\n", __func__,
-                         info->qos ? "true" : "false");
+               brcms_err(core, "%s: qos enabled: %s (implement)\n",
+                         __func__, info->qos ? "true" : "false");
        }
        return;
 }
@@ -553,25 +560,25 @@ brcms_ops_configure_filter(struct ieee80211_hw *hw,
                        unsigned int *total_flags, u64 multicast)
 {
        struct brcms_info *wl = hw->priv;
-       struct wiphy *wiphy = hw->wiphy;
+       struct bcma_device *core = wl->wlc->hw->d11core;
 
        changed_flags &= MAC_FILTERS;
        *total_flags &= MAC_FILTERS;
 
        if (changed_flags & FIF_PROMISC_IN_BSS)
-               wiphy_dbg(wiphy, "FIF_PROMISC_IN_BSS\n");
+               brcms_dbg_info(core, "FIF_PROMISC_IN_BSS\n");
        if (changed_flags & FIF_ALLMULTI)
-               wiphy_dbg(wiphy, "FIF_ALLMULTI\n");
+               brcms_dbg_info(core, "FIF_ALLMULTI\n");
        if (changed_flags & FIF_FCSFAIL)
-               wiphy_dbg(wiphy, "FIF_FCSFAIL\n");
+               brcms_dbg_info(core, "FIF_FCSFAIL\n");
        if (changed_flags & FIF_CONTROL)
-               wiphy_dbg(wiphy, "FIF_CONTROL\n");
+               brcms_dbg_info(core, "FIF_CONTROL\n");
        if (changed_flags & FIF_OTHER_BSS)
-               wiphy_dbg(wiphy, "FIF_OTHER_BSS\n");
+               brcms_dbg_info(core, "FIF_OTHER_BSS\n");
        if (changed_flags & FIF_PSPOLL)
-               wiphy_dbg(wiphy, "FIF_PSPOLL\n");
+               brcms_dbg_info(core, "FIF_PSPOLL\n");
        if (changed_flags & FIF_BCN_PRBRESP_PROMISC)
-               wiphy_dbg(wiphy, "FIF_BCN_PRBRESP_PROMISC\n");
+               brcms_dbg_info(core, "FIF_BCN_PRBRESP_PROMISC\n");
 
        spin_lock_bh(&wl->lock);
        brcms_c_mac_promisc(wl->wlc, *total_flags);
@@ -653,8 +660,8 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
                status = brcms_c_aggregatable(wl->wlc, tid);
                spin_unlock_bh(&wl->lock);
                if (!status) {
-                       wiphy_err(wl->wiphy, "START: tid %d is not agg\'able\n",
-                                 tid);
+                       brcms_err(wl->wlc->hw->d11core,
+                                 "START: tid %d is not agg\'able\n", tid);
                        return -EINVAL;
                }
                ieee80211_start_tx_ba_cb_irqsafe(vif, sta->addr, tid);
@@ -681,8 +688,8 @@ brcms_ops_ampdu_action(struct ieee80211_hw *hw,
                /* Power save wakeup */
                break;
        default:
-               wiphy_err(wl->wiphy, "%s: Invalid command, ignoring\n",
-                         __func__);
+               brcms_err(wl->wlc->hw->d11core,
+                         "%s: Invalid command, ignoring\n", __func__);
        }
 
        return 0;
@@ -1144,14 +1151,13 @@ static int brcms_suspend(struct bcma_device *pdev)
        wl->pub->hw_up = false;
        spin_unlock_bh(&wl->lock);
 
-       pr_debug("brcms_suspend ok\n");
+       brcms_dbg_info(wl->wlc->hw->d11core, "brcms_suspend ok\n");
 
        return 0;
 }
 
 static int brcms_resume(struct bcma_device *pdev)
 {
-       pr_debug("brcms_resume ok\n");
        return 0;
 }
 
@@ -1184,10 +1190,6 @@ static DECLARE_WORK(brcms_driver_work, brcms_driver_init);
 
 static int __init brcms_module_init(void)
 {
-#ifdef DEBUG
-       if (msglevel != 0xdeadbeef)
-               brcm_msg_level = msglevel;
-#endif
        if (!schedule_work(&brcms_driver_work))
                return -EBUSY;
 
@@ -1216,7 +1218,7 @@ module_exit(brcms_module_exit);
 void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,
                         bool state, int prio)
 {
-       wiphy_err(wl->wiphy, "Shouldn't be here %s\n", __func__);
+       brcms_err(wl->wlc->hw->d11core, "Shouldn't be here %s\n", __func__);
 }
 
 /*
@@ -1224,7 +1226,8 @@ void brcms_txflowcontrol(struct brcms_info *wl, struct brcms_if *wlif,
  */
 void brcms_init(struct brcms_info *wl)
 {
-       BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
+       brcms_dbg_info(wl->wlc->hw->d11core, "Initializing wl%d\n",
+                      wl->pub->unit);
        brcms_reset(wl);
        brcms_c_init(wl->wlc, wl->mute_tx);
 }
@@ -1234,7 +1237,7 @@ void brcms_init(struct brcms_info *wl)
  */
 uint brcms_reset(struct brcms_info *wl)
 {
-       BCMMSG(wl->pub->ieee_hw->wiphy, "wl%d\n", wl->pub->unit);
+       brcms_dbg_info(wl->wlc->hw->d11core, "Resetting wl%d\n", wl->pub->unit);
        brcms_c_reset(wl->wlc);
 
        /* dpc will not be rescheduled */
@@ -1248,7 +1251,7 @@ uint brcms_reset(struct brcms_info *wl)
 
 void brcms_fatal_error(struct brcms_info *wl)
 {
-       wiphy_err(wl->wlc->wiphy, "wl%d: fatal error, reinitializing\n",
+       brcms_err(wl->wlc->hw->d11core, "wl%d: fatal error, reinitializing\n",
                  wl->wlc->pub->unit);
        brcms_reset(wl);
        ieee80211_restart_hw(wl->pub->ieee_hw);
@@ -1396,8 +1399,9 @@ void brcms_add_timer(struct brcms_timer *t, uint ms, int periodic)
 
 #ifdef DEBUG
        if (t->set)
-               wiphy_err(hw->wiphy, "%s: Already set. Name: %s, per %d\n",
-                         __func__, t->name, periodic);
+               brcms_dbg_info(t->wl->wlc->hw->d11core,
+                              "%s: Already set. Name: %s, per %d\n",
+                              __func__, t->name, periodic);
 #endif
        t->ms = ms;
        t->periodic = (bool) periodic;
@@ -1486,8 +1490,8 @@ int brcms_ucode_init_buf(struct brcms_info *wl, void **pbuf, u32 idx)
                        }
                }
        }
-       wiphy_err(wl->wiphy, "ERROR: ucode buf tag:%d can not be found!\n",
-                 idx);
+       brcms_err(wl->wlc->hw->d11core,
+                 "ERROR: ucode buf tag:%d can not be found!\n", idx);
        *pbuf = NULL;
 fail:
        return -ENODATA;
@@ -1510,7 +1514,7 @@ int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx)
                                pdata = wl->fw.fw_bin[i]->data +
                                        le32_to_cpu(hdr->offset);
                                if (le32_to_cpu(hdr->len) != 4) {
-                                       wiphy_err(wl->wiphy,
+                                       brcms_err(wl->wlc->hw->d11core,
                                                  "ERROR: fw hdr len\n");
                                        return -ENOMSG;
                                }
@@ -1519,7 +1523,8 @@ int brcms_ucode_init_uint(struct brcms_info *wl, size_t *n_bytes, u32 idx)
                        }
                }
        }
-       wiphy_err(wl->wiphy, "ERROR: ucode tag:%d can not be found!\n", idx);
+       brcms_err(wl->wlc->hw->d11core,
+                 "ERROR: ucode tag:%d can not be found!\n", idx);
        return -ENOMSG;
 }
 
@@ -1560,8 +1565,8 @@ int brcms_check_firmwares(struct brcms_info *wl)
                                sizeof(struct firmware_hdr));
                        rc = -EBADF;
                } else if (fw->size < MIN_FW_SIZE || fw->size > MAX_FW_SIZE) {
-                       wiphy_err(wl->wiphy, "%s: out of bounds fw file size "
-                                 "%zu\n", __func__, fw->size);
+                       wiphy_err(wl->wiphy, "%s: out of bounds fw file size %zu\n",
+                                 __func__, fw->size);
                        rc = -EBADF;
                } else {
                        /* check if ucode section overruns firmware image */
index 565c15abbed546cf4bfe6acb3771dcf34f45f1ad..2a44593f1e37152999486f7e045219f03d0ae1b5 100644 (file)
 #include "ucode_loader.h"
 #include "main.h"
 #include "soc.h"
-
-/*
- * Indication for txflowcontrol that all priority bits in
- * TXQ_STOP_FOR_PRIOFC_MASK are to be considered.
- */
-#define ALLPRIO                                -1
+#include "dma.h"
+#include "debug.h"
+#include "brcms_trace_events.h"
 
 /* watchdog timer, in unit of ms */
 #define TIMER_INTERVAL_WATCHDOG                1000
 
 #define BRCMS_TEMPSENSE_PERIOD         10      /* 10 second timeout */
 
-/* precedences numbers for wlc queues. These are twice as may levels as
- * 802.1D priorities.
- * Odd numbers are used for HI priority traffic at same precedence levels
- * These constants are used ONLY by wlc_prio2prec_map.  Do not use them
- * elsewhere.
- */
-#define _BRCMS_PREC_NONE               0       /* None = - */
-#define _BRCMS_PREC_BK                 2       /* BK - Background */
-#define _BRCMS_PREC_BE                 4       /* BE - Best-effort */
-#define _BRCMS_PREC_EE                 6       /* EE - Excellent-effort */
-#define _BRCMS_PREC_CL                 8       /* CL - Controlled Load */
-#define _BRCMS_PREC_VI                 10      /* Vi - Video */
-#define _BRCMS_PREC_VO                 12      /* Vo - Voice */
-#define _BRCMS_PREC_NC                 14      /* NC - Network Control */
-
 /* synthpu_dly times in us */
 #define SYNTHPU_DLY_APHY_US            3700
 #define SYNTHPU_DLY_BPHY_US            1050
 
 #define MAX_DMA_SEGS                   4
 
-/* Max # of entries in Tx FIFO based on 4kb page size */
-#define NTXD                           256
+/* # of entries in Tx FIFO */
+#define NTXD                           64
 /* Max # of entries in Rx FIFO based on 4kb page size */
 #define NRXD                           256
 
+/* Amount of headroom to leave in Tx FIFO */
+#define TX_HEADROOM                    4
+
 /* try to keep this # rbufs posted to the chip */
 #define NRXBUFPOST                     32
 
-/* data msg txq hiwat mark */
-#define BRCMS_DATAHIWAT                        50
-
 /* max # frames to process in brcms_c_recv() */
 #define RXBND                          8
 /* max # tx status to process in wlc_txstatus() */
@@ -283,24 +265,8 @@ struct edcf_acparam {
        u16 TXOP;
 } __packed;
 
-const u8 prio2fifo[NUMPRIO] = {
-       TX_AC_BE_FIFO,          /* 0    BE      AC_BE   Best Effort */
-       TX_AC_BK_FIFO,          /* 1    BK      AC_BK   Background */
-       TX_AC_BK_FIFO,          /* 2    --      AC_BK   Background */
-       TX_AC_BE_FIFO,          /* 3    EE      AC_BE   Best Effort */
-       TX_AC_VI_FIFO,          /* 4    CL      AC_VI   Video */
-       TX_AC_VI_FIFO,          /* 5    VI      AC_VI   Video */
-       TX_AC_VO_FIFO,          /* 6    VO      AC_VO   Voice */
-       TX_AC_VO_FIFO           /* 7    NC      AC_VO   Voice */
-};
-
 /* debug/trace */
-uint brcm_msg_level =
-#if defined(DEBUG)
-       LOG_ERROR_VAL;
-#else
-       0;
-#endif                         /* DEBUG */
+uint brcm_msg_level;
 
 /* TX FIFO number to WME/802.1E Access Category */
 static const u8 wme_fifo2ac[] = {
@@ -320,18 +286,6 @@ static const u8 wme_ac2fifo[] = {
        TX_AC_BK_FIFO
 };
 
-/* 802.1D Priority to precedence queue mapping */
-const u8 wlc_prio2prec_map[] = {
-       _BRCMS_PREC_BE,         /* 0 BE - Best-effort */
-       _BRCMS_PREC_BK,         /* 1 BK - Background */
-       _BRCMS_PREC_NONE,               /* 2 None = - */
-       _BRCMS_PREC_EE,         /* 3 EE - Excellent-effort */
-       _BRCMS_PREC_CL,         /* 4 CL - Controlled Load */
-       _BRCMS_PREC_VI,         /* 5 Vi - Video */
-       _BRCMS_PREC_VO,         /* 6 Vo - Voice */
-       _BRCMS_PREC_NC,         /* 7 NC - Network Control */
-};
-
 static const u16 xmtfifo_sz[][NFIFO] = {
        /* corerev 17: 5120, 49152, 49152, 5376, 4352, 1280 */
        {20, 192, 192, 21, 17, 5},
@@ -371,6 +325,36 @@ static const char fifo_names[6][0];
 static struct brcms_c_info *wlc_info_dbg = (struct brcms_c_info *) (NULL);
 #endif
 
+/* Mapping of ieee80211 AC numbers to tx fifos */
+static const u8 ac_to_fifo_mapping[IEEE80211_NUM_ACS] = {
+       [IEEE80211_AC_VO]       = TX_AC_VO_FIFO,
+       [IEEE80211_AC_VI]       = TX_AC_VI_FIFO,
+       [IEEE80211_AC_BE]       = TX_AC_BE_FIFO,
+       [IEEE80211_AC_BK]       = TX_AC_BK_FIFO,
+};
+
+/* Mapping of tx fifos to ieee80211 AC numbers */
+static const u8 fifo_to_ac_mapping[IEEE80211_NUM_ACS] = {
+       [TX_AC_BK_FIFO] = IEEE80211_AC_BK,
+       [TX_AC_BE_FIFO] = IEEE80211_AC_BE,
+       [TX_AC_VI_FIFO] = IEEE80211_AC_VI,
+       [TX_AC_VO_FIFO] = IEEE80211_AC_VO,
+};
+
+static u8 brcms_ac_to_fifo(u8 ac)
+{
+       if (ac >= ARRAY_SIZE(ac_to_fifo_mapping))
+               return TX_AC_BE_FIFO;
+       return ac_to_fifo_mapping[ac];
+}
+
+static u8 brcms_fifo_to_ac(u8 fifo)
+{
+       if (fifo >= ARRAY_SIZE(fifo_to_ac_mapping))
+               return IEEE80211_AC_BE;
+       return fifo_to_ac_mapping[fifo];
+}
+
 /* Find basic rate for a given rate */
 static u8 brcms_basic_rate(struct brcms_c_info *wlc, u32 rspec)
 {
@@ -415,10 +399,15 @@ static bool brcms_deviceremoved(struct brcms_c_info *wlc)
 }
 
 /* sum the individual fifo tx pending packet counts */
-static s16 brcms_txpktpendtot(struct brcms_c_info *wlc)
+static int brcms_txpktpendtot(struct brcms_c_info *wlc)
 {
-       return wlc->core->txpktpend[0] + wlc->core->txpktpend[1] +
-              wlc->core->txpktpend[2] + wlc->core->txpktpend[3];
+       int i;
+       int pending = 0;
+
+       for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++)
+               if (wlc->hw->di[i])
+                       pending += dma_txpending(wlc->hw->di[i]);
+       return pending;
 }
 
 static bool brcms_is_mband_unlocked(struct brcms_c_info *wlc)
@@ -626,14 +615,11 @@ static uint brcms_c_calc_frame_time(struct brcms_c_info *wlc, u32 ratespec,
        uint rate = rspec2rate(ratespec);
 
        if (rate == 0) {
-               wiphy_err(wlc->wiphy, "wl%d: WAR: using rate of 1 mbps\n",
+               brcms_err(wlc->hw->d11core, "wl%d: WAR: using rate of 1 mbps\n",
                          wlc->pub->unit);
                rate = BRCM_RATE_1M;
        }
 
-       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, len%d\n",
-                wlc->pub->unit, ratespec, preamble_type, mac_len);
-
        if (is_mcs_rate(ratespec)) {
                uint mcs = ratespec & RSPEC_RATE_MASK;
                int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
@@ -696,7 +682,7 @@ static void brcms_c_write_inits(struct brcms_hardware *wlc_hw,
        u16 size;
        u32 value;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
 
        for (i = 0; inits[i].addr != cpu_to_le16(0xffff); i++) {
                size = le16_to_cpu(inits[i].size);
@@ -725,7 +711,6 @@ static void brcms_c_write_mhf(struct brcms_hardware *wlc_hw, u16 *mhfs)
 
 static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
 {
-       struct wiphy *wiphy = wlc_hw->wlc->wiphy;
        struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
 
        /* init microcode host flags */
@@ -736,8 +721,9 @@ static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
                if (BRCMS_ISNPHY(wlc_hw->band))
                        brcms_c_write_inits(wlc_hw, ucode->d11n0bsinitvals16);
                else
-                       wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
-                                 " %d\n", __func__, wlc_hw->unit,
+                       brcms_err(wlc_hw->d11core,
+                                 "%s: wl%d: unsupported phy in corerev %d\n",
+                                 __func__, wlc_hw->unit,
                                  wlc_hw->corerev);
        } else {
                if (D11REV_IS(wlc_hw->corerev, 24)) {
@@ -745,12 +731,14 @@ static void brcms_c_ucode_bsinit(struct brcms_hardware *wlc_hw)
                                brcms_c_write_inits(wlc_hw,
                                                    ucode->d11lcn0bsinitvals24);
                        else
-                               wiphy_err(wiphy, "%s: wl%d: unsupported phy in"
-                                         " core rev %d\n", __func__,
-                                         wlc_hw->unit, wlc_hw->corerev);
+                               brcms_err(wlc_hw->d11core,
+                                         "%s: wl%d: unsupported phy in core rev %d\n",
+                                         __func__, wlc_hw->unit,
+                                         wlc_hw->corerev);
                } else {
-                       wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
-                               __func__, wlc_hw->unit, wlc_hw->corerev);
+                       brcms_err(wlc_hw->d11core,
+                                 "%s: wl%d: unsupported corerev %d\n",
+                                 __func__, wlc_hw->unit, wlc_hw->corerev);
                }
        }
 }
@@ -765,7 +753,7 @@ static void brcms_b_core_ioctl(struct brcms_hardware *wlc_hw, u32 m, u32 v)
 
 static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
 {
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: clk %d\n", wlc_hw->unit, clk);
+       brcms_dbg_info(wlc_hw->d11core, "wl%d: clk %d\n", wlc_hw->unit, clk);
 
        wlc_hw->phyclk = clk;
 
@@ -790,8 +778,8 @@ static void brcms_b_core_phy_clk(struct brcms_hardware *wlc_hw, bool clk)
 /* low-level band switch utility routine */
 static void brcms_c_setxband(struct brcms_hardware *wlc_hw, uint bandunit)
 {
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
-               bandunit);
+       brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: bandunit %d\n", wlc_hw->unit,
+                          bandunit);
 
        wlc_hw->band = wlc_hw->bandstate[bandunit];
 
@@ -819,7 +807,7 @@ static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
        u32 macintmask;
        u32 macctrl;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_mac80211(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
        macctrl = bcma_read32(wlc_hw->d11core,
                              D11REGOFFS(maccontrol));
        WARN_ON((macctrl & MCTL_EN_MAC) != 0);
@@ -841,9 +829,10 @@ static u32 brcms_c_setband_inact(struct brcms_c_info *wlc, uint bandunit)
 static bool
 brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
 {
-       struct sk_buff *p;
-       uint queue;
-       struct d11txh *txh;
+       struct sk_buff *p = NULL;
+       uint queue = NFIFO;
+       struct dma_pub *dma = NULL;
+       struct d11txh *txh = NULL;
        struct scb *scb = NULL;
        bool free_pdu;
        int tx_rts, tx_frame_count, tx_rts_count;
@@ -854,6 +843,11 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
        struct ieee80211_tx_info *tx_info;
        struct ieee80211_tx_rate *txrate;
        int i;
+       bool fatal = true;
+
+       trace_brcms_txstatus(&wlc->hw->d11core->dev, txs->framelen,
+                            txs->frameid, txs->status, txs->lasttxtime,
+                            txs->sequence, txs->phyerr, txs->ackphyrxsh);
 
        /* discard intermediate indications for ucode with one legitimate case:
         *   e.g. if "useRTS" is set. ucode did a successful rts/cts exchange,
@@ -862,34 +856,36 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
         */
        if (!(txs->status & TX_STATUS_AMPDU)
            && (txs->status & TX_STATUS_INTERMEDIATE)) {
-               BCMMSG(wlc->wiphy, "INTERMEDIATE but not AMPDU\n");
-               return false;
+               brcms_dbg_tx(wlc->hw->d11core, "INTERMEDIATE but not AMPDU\n");
+               fatal = false;
+               goto out;
        }
 
        queue = txs->frameid & TXFID_QUEUE_MASK;
        if (queue >= NFIFO) {
-               p = NULL;
-               goto fatal;
+               brcms_err(wlc->hw->d11core, "queue %u >= NFIFO\n", queue);
+               goto out;
        }
 
+       dma = wlc->hw->di[queue];
+
        p = dma_getnexttxp(wlc->hw->di[queue], DMA_RANGE_TRANSMITTED);
-       if (p == NULL)
-               goto fatal;
+       if (p == NULL) {
+               brcms_err(wlc->hw->d11core, "dma_getnexttxp returned null!\n");
+               goto out;
+       }
 
        txh = (struct d11txh *) (p->data);
        mcl = le16_to_cpu(txh->MacTxControlLow);
 
-       if (txs->phyerr) {
-               if (brcm_msg_level & LOG_ERROR_VAL) {
-                       wiphy_err(wlc->wiphy, "phyerr 0x%x, rate 0x%x\n",
-                                 txs->phyerr, txh->MainRates);
-                       brcms_c_print_txdesc(txh);
-               }
-               brcms_c_print_txstatus(txs);
-       }
+       if (txs->phyerr)
+               brcms_err(wlc->hw->d11core, "phyerr 0x%x, rate 0x%x\n",
+                         txs->phyerr, txh->MainRates);
 
-       if (txs->frameid != le16_to_cpu(txh->TxFrameID))
-               goto fatal;
+       if (txs->frameid != le16_to_cpu(txh->TxFrameID)) {
+               brcms_err(wlc->hw->d11core, "frameid != txh->TxFrameID\n");
+               goto out;
+       }
        tx_info = IEEE80211_SKB_CB(p);
        h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
 
@@ -898,14 +894,24 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
 
        if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
                brcms_c_ampdu_dotxstatus(wlc->ampdu, scb, p, txs);
-               return false;
+               fatal = false;
+               goto out;
        }
 
+       /*
+        * brcms_c_ampdu_dotxstatus() will trace tx descriptors for AMPDU
+        * frames; this traces them for the rest.
+        */
+       trace_brcms_txdesc(&wlc->hw->d11core->dev, txh, sizeof(*txh));
+
        supr_status = txs->status & TX_STATUS_SUPR_MASK;
-       if (supr_status == TX_STATUS_SUPR_BADCH)
-               BCMMSG(wlc->wiphy,
-                      "%s: Pkt tx suppressed, possibly channel %d\n",
-                      __func__, CHSPEC_CHANNEL(wlc->default_bss->chanspec));
+       if (supr_status == TX_STATUS_SUPR_BADCH) {
+               unsigned xfts = le16_to_cpu(txh->XtraFrameTypes);
+               brcms_dbg_tx(wlc->hw->d11core,
+                            "Pkt tx suppressed, dest chan %u, current %d\n",
+                            (xfts >> XFTS_CHANNEL_SHIFT) & 0xff,
+                            CHSPEC_CHANNEL(wlc->default_bss->chanspec));
+       }
 
        tx_rts = le16_to_cpu(txh->MacTxControlLow) & TXC_SENDRTS;
        tx_frame_count =
@@ -916,7 +922,7 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
        lastframe = !ieee80211_has_morefrags(h->frame_control);
 
        if (!lastframe) {
-               wiphy_err(wlc->wiphy, "Not last frame!\n");
+               brcms_err(wlc->hw->d11core, "Not last frame!\n");
        } else {
                /*
                 * Set information to be consumed by Minstrel ht.
@@ -982,26 +988,37 @@ brcms_c_dotxstatus(struct brcms_c_info *wlc, struct tx_status *txs)
        totlen = p->len;
        free_pdu = true;
 
-       brcms_c_txfifo_complete(wlc, queue, 1);
-
        if (lastframe) {
                /* remove PLCP & Broadcom tx descriptor header */
                skb_pull(p, D11_PHY_HDR_LEN);
                skb_pull(p, D11_TXH_LEN);
                ieee80211_tx_status_irqsafe(wlc->pub->ieee_hw, p);
        } else {
-               wiphy_err(wlc->wiphy, "%s: Not last frame => not calling "
-                         "tx_status\n", __func__);
+               brcms_err(wlc->hw->d11core,
+                         "%s: Not last frame => not calling tx_status\n",
+                         __func__);
        }
 
-       return false;
+       fatal = false;
 
- fatal:
-       if (p)
-               brcmu_pkt_buf_free_skb(p);
+ out:
+       if (fatal) {
+               if (txh)
+                       trace_brcms_txdesc(&wlc->hw->d11core->dev, txh,
+                                          sizeof(*txh));
+               if (p)
+                       brcmu_pkt_buf_free_skb(p);
+       }
 
-       return true;
+       if (dma && queue < NFIFO) {
+               u16 ac_queue = brcms_fifo_to_ac(queue);
+               if (dma->txavail > TX_HEADROOM && queue < TX_BCMC_FIFO &&
+                   ieee80211_queue_stopped(wlc->pub->ieee_hw, ac_queue))
+                       ieee80211_wake_queue(wlc->pub->ieee_hw, ac_queue);
+               dma_kick_tx(dma);
+       }
 
+       return fatal;
 }
 
 /* process tx completion events in BMAC
@@ -1011,7 +1028,6 @@ static bool
 brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
 {
        bool morepending = false;
-       struct brcms_c_info *wlc = wlc_hw->wlc;
        struct bcma_device *core;
        struct tx_status txstatus, *txs;
        u32 s1, s2;
@@ -1022,8 +1038,6 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
         */
        uint max_tx_num = bound ? TXSBND : -1;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
        txs = &txstatus;
        core = wlc_hw->d11core;
        *fatal = false;
@@ -1032,8 +1046,8 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
               && (s1 & TXS_V)) {
 
                if (s1 == 0xffffffff) {
-                       wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n",
-                               wlc_hw->unit, __func__);
+                       brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
+                                 __func__);
                        return morepending;
                }
                s2 = bcma_read32(core, D11REGOFFS(frmtxstatus2));
@@ -1058,9 +1072,6 @@ brcms_b_txstatus(struct brcms_hardware *wlc_hw, bool bound, bool *fatal)
        if (n >= max_tx_num)
                morepending = true;
 
-       if (!pktq_empty(&wlc->pkt_queue->q))
-               brcms_c_send_q(wlc);
-
        return morepending;
 }
 
@@ -1112,7 +1123,6 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
        u16 pio_mhf2 = 0;
        struct brcms_hardware *wlc_hw = wlc->hw;
        uint unit = wlc_hw->unit;
-       struct wiphy *wiphy = wlc->wiphy;
 
        /* name and offsets for dma_attach */
        snprintf(name, sizeof(name), "wl%d", unit);
@@ -1125,12 +1135,12 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
                 * TX: TX_AC_BK_FIFO (TX AC Background data packets)
                 * RX: RX_FIFO (RX data packets)
                 */
-               wlc_hw->di[0] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core,
+               wlc_hw->di[0] = dma_attach(name, wlc,
                                           (wme ? dmareg(DMA_TX, 0) : 0),
                                           dmareg(DMA_RX, 0),
                                           (wme ? NTXD : 0), NRXD,
                                           RXBUFSZ, -1, NRXBUFPOST,
-                                          BRCMS_HWRXOFF, &brcm_msg_level);
+                                          BRCMS_HWRXOFF);
                dma_attach_err |= (NULL == wlc_hw->di[0]);
 
                /*
@@ -1139,10 +1149,9 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
                 *   (legacy) TX_DATA_FIFO (TX data packets)
                 * RX: UNUSED
                 */
-               wlc_hw->di[1] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core,
+               wlc_hw->di[1] = dma_attach(name, wlc,
                                           dmareg(DMA_TX, 1), 0,
-                                          NTXD, 0, 0, -1, 0, 0,
-                                          &brcm_msg_level);
+                                          NTXD, 0, 0, -1, 0, 0);
                dma_attach_err |= (NULL == wlc_hw->di[1]);
 
                /*
@@ -1150,26 +1159,26 @@ static bool brcms_b_attach_dmapio(struct brcms_c_info *wlc, uint j, bool wme)
                 * TX: TX_AC_VI_FIFO (TX AC Video data packets)
                 * RX: UNUSED
                 */
-               wlc_hw->di[2] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core,
+               wlc_hw->di[2] = dma_attach(name, wlc,
                                           dmareg(DMA_TX, 2), 0,
-                                          NTXD, 0, 0, -1, 0, 0,
-                                          &brcm_msg_level);
+                                          NTXD, 0, 0, -1, 0, 0);
                dma_attach_err |= (NULL == wlc_hw->di[2]);
                /*
                 * FIFO 3
                 * TX: TX_AC_VO_FIFO (TX AC Voice data packets)
                 *   (legacy) TX_CTL_FIFO (TX control & mgmt packets)
                 */
-               wlc_hw->di[3] = dma_attach(name, wlc_hw->sih, wlc_hw->d11core,
+               wlc_hw->di[3] = dma_attach(name, wlc,
                                           dmareg(DMA_TX, 3),
                                           0, NTXD, 0, 0, -1,
-                                          0, 0, &brcm_msg_level);
+                                          0, 0);
                dma_attach_err |= (NULL == wlc_hw->di[3]);
 /* Cleaner to leave this as if with AP defined */
 
                if (dma_attach_err) {
-                       wiphy_err(wiphy, "wl%d: wlc_attach: dma_attach failed"
-                                 "\n", unit);
+                       brcms_err(wlc_hw->d11core,
+                                 "wl%d: wlc_attach: dma_attach failed\n",
+                                 unit);
                        return false;
                }
 
@@ -1503,8 +1512,7 @@ brcms_b_set_addrmatch(struct brcms_hardware *wlc_hw, int match_reg_offset,
        u16 mac_m;
        u16 mac_h;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: brcms_b_set_addrmatch\n",
-                wlc_hw->unit);
+       brcms_dbg_rx(core, "wl%d: brcms_b_set_addrmatch\n", wlc_hw->unit);
 
        mac_l = addr[0] | (addr[1] << 8);
        mac_m = addr[2] | (addr[3] << 8);
@@ -1527,7 +1535,7 @@ brcms_b_write_template_ram(struct brcms_hardware *wlc_hw, int offset, int len,
        __le32 word_le;
        __be32 word_be;
        bool be_bit;
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(core, "wl%d\n", wlc_hw->unit);
 
        bcma_write32(core, D11REGOFFS(tplatewrptr), offset);
 
@@ -1700,8 +1708,8 @@ static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)
 {
        struct brcms_hardware *wlc_hw = wlc->hw;
 
-       BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
-               wlc_hw->band->bandunit);
+       brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: bandunit %d\n", wlc_hw->unit,
+                          wlc_hw->band->bandunit);
 
        brcms_c_ucode_bsinit(wlc_hw);
 
@@ -1736,8 +1744,6 @@ static void brcms_b_bsinit(struct brcms_c_info *wlc, u16 chanspec)
 /* Perform a soft reset of the PHY PLL */
 void brcms_b_core_phypll_reset(struct brcms_hardware *wlc_hw)
 {
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
        ai_cc_reg(wlc_hw->sih, offsetof(struct chipcregs, chipcontrol_addr),
                  ~0, 0);
        udelay(1);
@@ -1782,7 +1788,7 @@ void brcms_b_phy_reset(struct brcms_hardware *wlc_hw)
        u32 phy_bw_clkbits;
        bool phy_in_reset = false;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(wlc_hw->d11core, "wl%d: reset phy\n", wlc_hw->unit);
 
        if (pih == NULL)
                return;
@@ -1916,7 +1922,7 @@ static void brcms_c_get_macaddr(struct brcms_hardware *wlc_hw, u8 etheraddr[ETH_
 /* power both the pll and external oscillator on/off */
 static void brcms_b_xtal(struct brcms_hardware *wlc_hw, bool want)
 {
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: want %d\n", wlc_hw->unit, want);
+       brcms_dbg_info(wlc_hw->d11core, "wl%d: want %d\n", wlc_hw->unit, want);
 
        /*
         * dont power down if plldown is false or
@@ -2005,7 +2011,7 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
        if (flags == BRCMS_USE_COREFLAGS)
                flags = (wlc_hw->band->pi ? wlc_hw->band->core_flags : 0);
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(wlc_hw->d11core, "wl%d: core reset\n", wlc_hw->unit);
 
        /* request FAST clock if not on  */
        fastclk = wlc_hw->forcefastclk;
@@ -2016,13 +2022,13 @@ void brcms_b_corereset(struct brcms_hardware *wlc_hw, u32 flags)
        if (bcma_core_is_enabled(wlc_hw->d11core)) {
                for (i = 0; i < NFIFO; i++)
                        if ((wlc_hw->di[i]) && (!dma_txreset(wlc_hw->di[i])))
-                               wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: "
+                               brcms_err(wlc_hw->d11core, "wl%d: %s: "
                                          "dma_txreset[%d]: cannot stop dma\n",
                                           wlc_hw->unit, __func__, i);
 
                if ((wlc_hw->di[RX_FIFO])
                    && (!wlc_dma_rxreset(wlc_hw, RX_FIFO)))
-                       wiphy_err(wlc_hw->wlc->wiphy, "wl%d: %s: dma_rxreset"
+                       brcms_err(wlc_hw->d11core, "wl%d: %s: dma_rxreset"
                                  "[%d]: cannot stop dma\n",
                                  wlc_hw->unit, __func__, RX_FIFO);
        }
@@ -2235,7 +2241,7 @@ static void brcms_ucode_write(struct brcms_hardware *wlc_hw,
        uint i;
        uint count;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
 
        count = (nbytes / sizeof(u32));
 
@@ -2263,8 +2269,8 @@ static void brcms_ucode_download(struct brcms_hardware *wlc_hw)
                                          ucode->bcm43xx_16_mimosz);
                        wlc_hw->ucode_loaded = true;
                } else
-                       wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
-                                 "corerev %d\n",
+                       brcms_err(wlc_hw->d11core,
+                                 "%s: wl%d: unsupported phy in corerev %d\n",
                                  __func__, wlc_hw->unit, wlc_hw->corerev);
        } else if (D11REV_IS(wlc_hw->corerev, 24)) {
                if (BRCMS_ISLCNPHY(wlc_hw->band)) {
@@ -2272,8 +2278,8 @@ static void brcms_ucode_download(struct brcms_hardware *wlc_hw)
                                          ucode->bcm43xx_24_lcnsz);
                        wlc_hw->ucode_loaded = true;
                } else {
-                       wiphy_err(wlc->wiphy, "%s: wl%d: unsupported phy in "
-                                 "corerev %d\n",
+                       brcms_err(wlc_hw->d11core,
+                                 "%s: wl%d: unsupported phy in corerev %d\n",
                                  __func__, wlc_hw->unit, wlc_hw->corerev);
                }
        }
@@ -2310,7 +2316,6 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
        uint unit;
        uint intstatus, idx;
        struct bcma_device *core = wlc_hw->d11core;
-       struct wiphy *wiphy = wlc_hw->wlc->wiphy;
 
        unit = wlc_hw->unit;
 
@@ -2323,39 +2328,39 @@ static void brcms_b_fifoerrors(struct brcms_hardware *wlc_hw)
                if (!intstatus)
                        continue;
 
-               BCMMSG(wlc_hw->wlc->wiphy, "wl%d: intstatus%d 0x%x\n",
-                       unit, idx, intstatus);
+               brcms_dbg_int(core, "wl%d: intstatus%d 0x%x\n",
+                             unit, idx, intstatus);
 
                if (intstatus & I_RO) {
-                       wiphy_err(wiphy, "wl%d: fifo %d: receive fifo "
+                       brcms_err(core, "wl%d: fifo %d: receive fifo "
                                  "overflow\n", unit, idx);
                        fatal = true;
                }
 
                if (intstatus & I_PC) {
-                       wiphy_err(wiphy, "wl%d: fifo %d: descriptor error\n",
-                                unit, idx);
+                       brcms_err(core, "wl%d: fifo %d: descriptor error\n",
+                                 unit, idx);
                        fatal = true;
                }
 
                if (intstatus & I_PD) {
-                       wiphy_err(wiphy, "wl%d: fifo %d: data error\n", unit,
+                       brcms_err(core, "wl%d: fifo %d: data error\n", unit,
                                  idx);
                        fatal = true;
                }
 
                if (intstatus & I_DE) {
-                       wiphy_err(wiphy, "wl%d: fifo %d: descriptor protocol "
+                       brcms_err(core, "wl%d: fifo %d: descriptor protocol "
                                  "error\n", unit, idx);
                        fatal = true;
                }
 
                if (intstatus & I_RU)
-                       wiphy_err(wiphy, "wl%d: fifo %d: receive descriptor "
+                       brcms_err(core, "wl%d: fifo %d: receive descriptor "
                                  "underflow\n", idx, unit);
 
                if (intstatus & I_XU) {
-                       wiphy_err(wiphy, "wl%d: fifo %d: transmit fifo "
+                       brcms_err(core, "wl%d: fifo %d: transmit fifo "
                                  "underflow\n", idx, unit);
                        fatal = true;
                }
@@ -2516,13 +2521,13 @@ static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr)
 {
        struct brcms_hardware *wlc_hw = wlc->hw;
        struct bcma_device *core = wlc_hw->d11core;
-       u32 macintstatus;
+       u32 macintstatus, mask;
 
        /* macintstatus includes a DMA interrupt summary bit */
        macintstatus = bcma_read32(core, D11REGOFFS(macintstatus));
+       mask = in_isr ? wlc->macintmask : wlc->defmacintmask;
 
-       BCMMSG(wlc->wiphy, "wl%d: macintstatus: 0x%x\n", wlc_hw->unit,
-                macintstatus);
+       trace_brcms_macintstatus(&core->dev, in_isr, macintstatus, mask);
 
        /* detect cardbus removed, in power down(suspend) and in reset */
        if (brcms_deviceremoved(wlc))
@@ -2535,7 +2540,7 @@ static inline u32 wlc_intstatus(struct brcms_c_info *wlc, bool in_isr)
                return 0;
 
        /* defer unsolicited interrupts */
-       macintstatus &= (in_isr ? wlc->macintmask : wlc->defmacintmask);
+       macintstatus &= mask;
 
        /* if not for us */
        if (macintstatus == 0)
@@ -2605,8 +2610,8 @@ bool brcms_c_isr(struct brcms_c_info *wlc, bool *wantdpc)
        macintstatus = wlc_intstatus(wlc, true);
 
        if (macintstatus == 0xffffffff)
-               wiphy_err(wlc->wiphy, "DEVICEREMOVED detected in the ISR code"
-                         " path\n");
+               brcms_err(wlc_hw->d11core,
+                         "DEVICEREMOVED detected in the ISR code path\n");
 
        /* it is not for us */
        if (macintstatus == 0)
@@ -2626,10 +2631,9 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
        struct brcms_hardware *wlc_hw = wlc->hw;
        struct bcma_device *core = wlc_hw->d11core;
        u32 mc, mi;
-       struct wiphy *wiphy = wlc->wiphy;
 
-       BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
-               wlc_hw->band->bandunit);
+       brcms_dbg_mac80211(core, "wl%d: bandunit %d\n", wlc_hw->unit,
+                          wlc_hw->band->bandunit);
 
        /*
         * Track overlapping suspend requests
@@ -2644,7 +2648,7 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
        mc = bcma_read32(core, D11REGOFFS(maccontrol));
 
        if (mc == 0xffffffff) {
-               wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+               brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
                          __func__);
                brcms_down(wlc->wl);
                return;
@@ -2655,7 +2659,7 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
 
        mi = bcma_read32(core, D11REGOFFS(macintstatus));
        if (mi == 0xffffffff) {
-               wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+               brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
                          __func__);
                brcms_down(wlc->wl);
                return;
@@ -2668,10 +2672,10 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
                 BRCMS_MAX_MAC_SUSPEND);
 
        if (!(bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD)) {
-               wiphy_err(wiphy, "wl%d: wlc_suspend_mac_and_wait: waited %d uS"
+               brcms_err(core, "wl%d: wlc_suspend_mac_and_wait: waited %d uS"
                          " and MI_MACSSPNDD is still not on.\n",
                          wlc_hw->unit, BRCMS_MAX_MAC_SUSPEND);
-               wiphy_err(wiphy, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, "
+               brcms_err(core, "wl%d: psmdebug 0x%08x, phydebug 0x%08x, "
                          "psm_brc 0x%04x\n", wlc_hw->unit,
                          bcma_read32(core, D11REGOFFS(psmdebug)),
                          bcma_read32(core, D11REGOFFS(phydebug)),
@@ -2680,7 +2684,7 @@ void brcms_c_suspend_mac_and_wait(struct brcms_c_info *wlc)
 
        mc = bcma_read32(core, D11REGOFFS(maccontrol));
        if (mc == 0xffffffff) {
-               wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+               brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
                          __func__);
                brcms_down(wlc->wl);
                return;
@@ -2696,8 +2700,8 @@ void brcms_c_enable_mac(struct brcms_c_info *wlc)
        struct bcma_device *core = wlc_hw->d11core;
        u32 mc, mi;
 
-       BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n", wlc_hw->unit,
-               wlc->band->bandunit);
+       brcms_dbg_mac80211(core, "wl%d: bandunit %d\n", wlc_hw->unit,
+                          wlc->band->bandunit);
 
        /*
         * Track overlapping suspend requests
@@ -2740,8 +2744,6 @@ static bool brcms_b_validate_chip_access(struct brcms_hardware *wlc_hw)
        u32 w, val;
        struct wiphy *wiphy = wlc_hw->wlc->wiphy;
 
-       BCMMSG(wiphy, "wl%d\n", wlc_hw->unit);
-
        /* Validate dchip register access */
 
        bcma_write32(core, D11REGOFFS(objaddr), OBJADDR_SHM_SEL | 0);
@@ -2802,7 +2804,7 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)
        struct bcma_device *core = wlc_hw->d11core;
        u32 tmp;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(core, "wl%d\n", wlc_hw->unit);
 
        tmp = 0;
 
@@ -2818,8 +2820,8 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)
 
                        tmp = bcma_read32(core, D11REGOFFS(clk_ctl_st));
                        if ((tmp & CCS_ERSRC_AVAIL_HT) != CCS_ERSRC_AVAIL_HT)
-                               wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on PHY"
-                                         " PLL failed\n", __func__);
+                               brcms_err(core, "%s: turn on PHY PLL failed\n",
+                                         __func__);
                } else {
                        bcma_set32(core, D11REGOFFS(clk_ctl_st),
                                   tmp | CCS_ERSRC_REQ_D11PLL |
@@ -2835,8 +2837,8 @@ void brcms_b_core_phypll_ctl(struct brcms_hardware *wlc_hw, bool on)
                             (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
                            !=
                            (CCS_ERSRC_AVAIL_D11PLL | CCS_ERSRC_AVAIL_PHYPLL))
-                               wiphy_err(wlc_hw->wlc->wiphy, "%s: turn on "
-                                         "PHY PLL failed\n", __func__);
+                               brcms_err(core, "%s: turn on PHY PLL failed\n",
+                                         __func__);
                }
        } else {
                /*
@@ -2854,7 +2856,7 @@ static void brcms_c_coredisable(struct brcms_hardware *wlc_hw)
 {
        bool dev_gone;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(wlc_hw->d11core, "wl%d: disable core\n", wlc_hw->unit);
 
        dev_gone = brcms_deviceremoved(wlc_hw->wlc);
 
@@ -2884,12 +2886,14 @@ static void brcms_c_flushqueues(struct brcms_c_info *wlc)
        uint i;
 
        /* free any posted tx packets */
-       for (i = 0; i < NFIFO; i++)
+       for (i = 0; i < NFIFO; i++) {
                if (wlc_hw->di[i]) {
                        dma_txreclaim(wlc_hw->di[i], DMA_RANGE_ALL);
-                       wlc->core->txpktpend[i] = 0;
-                       BCMMSG(wlc->wiphy, "pktpend fifo %d clrd\n", i);
+                       if (i < TX_BCMC_FIFO)
+                               ieee80211_wake_queue(wlc->pub->ieee_hw,
+                                                    brcms_fifo_to_ac(i));
                }
+       }
 
        /* free any posted rx packets */
        dma_rxreclaim(wlc_hw->di[RX_FIFO]);
@@ -3109,7 +3113,7 @@ static void brcms_c_statsupd(struct brcms_c_info *wlc)
        /* check for rx fifo 0 overflow */
        delta = (u16) (wlc->core->macstat_snapshot->rxf0ovfl - rxf0ovfl);
        if (delta)
-               wiphy_err(wlc->wiphy, "wl%d: %u rx fifo 0 overflows!\n",
+               brcms_err(wlc->hw->d11core, "wl%d: %u rx fifo 0 overflows!\n",
                          wlc->pub->unit, delta);
 
        /* check for tx fifo underflows */
@@ -3118,8 +3122,9 @@ static void brcms_c_statsupd(struct brcms_c_info *wlc)
                    (u16) (wlc->core->macstat_snapshot->txfunfl[i] -
                              txfunfl[i]);
                if (delta)
-                       wiphy_err(wlc->wiphy, "wl%d: %u tx fifo %d underflows!"
-                                 "\n", wlc->pub->unit, delta, i);
+                       brcms_err(wlc->hw->d11core,
+                                 "wl%d: %u tx fifo %d underflows!\n",
+                                 wlc->pub->unit, delta, i);
        }
 #endif                         /* DEBUG */
 
@@ -3132,8 +3137,6 @@ static void brcms_c_statsupd(struct brcms_c_info *wlc)
 
 static void brcms_b_reset(struct brcms_hardware *wlc_hw)
 {
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
        /* reset the core */
        if (!brcms_deviceremoved(wlc_hw->wlc))
                brcms_b_corereset(wlc_hw, BRCMS_USE_COREFLAGS);
@@ -3144,7 +3147,7 @@ static void brcms_b_reset(struct brcms_hardware *wlc_hw)
 
 void brcms_c_reset(struct brcms_c_info *wlc)
 {
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+       brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);
 
        /* slurp up hw mac counters before core reset */
        brcms_c_statsupd(wlc);
@@ -3189,10 +3192,9 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc)
        bool fifosz_fixup = false;
        int err = 0;
        u16 buf[NFIFO];
-       struct wiphy *wiphy = wlc->wiphy;
        struct brcms_ucode *ucode = &wlc_hw->wlc->wl->ucode;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(core, "wl%d: core init\n", wlc_hw->unit);
 
        /* reset PSM */
        brcms_b_mctrl(wlc_hw, ~0, (MCTL_IHR_EN | MCTL_PSM_JMP_0 | MCTL_WAKE));
@@ -3212,7 +3214,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc)
        SPINWAIT(((bcma_read32(core, D11REGOFFS(macintstatus)) &
                   MI_MACSSPNDD) == 0), 1000 * 1000);
        if ((bcma_read32(core, D11REGOFFS(macintstatus)) & MI_MACSSPNDD) == 0)
-               wiphy_err(wiphy, "wl%d: wlc_coreinit: ucode did not self-"
+               brcms_err(core, "wl%d: wlc_coreinit: ucode did not self-"
                          "suspend!\n", wlc_hw->unit);
 
        brcms_c_gpio_init(wlc);
@@ -3223,18 +3225,18 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc)
                if (BRCMS_ISNPHY(wlc_hw->band))
                        brcms_c_write_inits(wlc_hw, ucode->d11n0initvals16);
                else
-                       wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
+                       brcms_err(core, "%s: wl%d: unsupported phy in corerev"
                                  " %d\n", __func__, wlc_hw->unit,
                                  wlc_hw->corerev);
        } else if (D11REV_IS(wlc_hw->corerev, 24)) {
                if (BRCMS_ISLCNPHY(wlc_hw->band))
                        brcms_c_write_inits(wlc_hw, ucode->d11lcn0initvals24);
                else
-                       wiphy_err(wiphy, "%s: wl%d: unsupported phy in corerev"
+                       brcms_err(core, "%s: wl%d: unsupported phy in corerev"
                                  " %d\n", __func__, wlc_hw->unit,
                                  wlc_hw->corerev);
        } else {
-               wiphy_err(wiphy, "%s: wl%d: unsupported corerev %d\n",
+               brcms_err(core, "%s: wl%d: unsupported corerev %d\n",
                          __func__, wlc_hw->unit, wlc_hw->corerev);
        }
 
@@ -3276,7 +3278,7 @@ static void brcms_b_coreinit(struct brcms_c_info *wlc)
                err = -1;
        }
        if (err != 0)
-               wiphy_err(wiphy, "wlc_coreinit: txfifo mismatch: ucode size %d"
+               brcms_err(core, "wlc_coreinit: txfifo mismatch: ucode size %d"
                          " driver size %d index %d\n", buf[i],
                          wlc_hw->xmtfifo_sz[i], i);
 
@@ -3359,8 +3361,6 @@ static brcms_b_init(struct brcms_hardware *wlc_hw, u16 chanspec) {
        bool fastclk;
        struct brcms_c_info *wlc = wlc_hw->wlc;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
        /* request FAST clock if not on */
        fastclk = wlc_hw->forcefastclk;
        if (!fastclk)
@@ -3453,7 +3453,7 @@ static void brcms_c_rate_lookup_init(struct brcms_c_info *wlc,
                rate = (rateset->rates[i] & BRCMS_RATE_MASK);
 
                if (rate > BRCM_MAXRATE) {
-                       wiphy_err(wlc->wiphy, "brcms_c_rate_lookup_init: "
+                       brcms_err(wlc->hw->d11core, "brcms_c_rate_lookup_init: "
                                  "invalid rate 0x%X in rate set\n",
                                  rateset->rates[i]);
                        continue;
@@ -3529,7 +3529,6 @@ static void brcms_c_bandinit_ordered(struct brcms_c_info *wlc,
        uint parkband;
        uint i, band_order[2];
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
        /*
         * We might have been bandlocked during down and the chip
         * power-cycled (hibernate). Figure out the right band to park on
@@ -3710,8 +3709,8 @@ static void brcms_c_set_ratetable(struct brcms_c_info *wlc)
 /* band-specific init */
 static void brcms_c_bsinit(struct brcms_c_info *wlc)
 {
-       BCMMSG(wlc->wiphy, "wl%d: bandunit %d\n",
-                wlc->pub->unit, wlc->band->bandunit);
+       brcms_dbg_info(wlc->hw->d11core, "wl%d: bandunit %d\n",
+                      wlc->pub->unit, wlc->band->bandunit);
 
        /* write ucode ACK/CTS rate table */
        brcms_c_set_ratetable(wlc);
@@ -3734,7 +3733,8 @@ brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
            isOFDM ? M_TX_IDLE_BUSY_RATIO_X_16_OFDM :
            M_TX_IDLE_BUSY_RATIO_X_16_CCK;
        if (duty_cycle > 100 || duty_cycle < 0) {
-               wiphy_err(wlc->wiphy, "wl%d:  duty cycle value off limit\n",
+               brcms_err(wlc->hw->d11core,
+                         "wl%d:  duty cycle value off limit\n",
                          wlc->pub->unit);
                return -EINVAL;
        }
@@ -3752,40 +3752,6 @@ brcms_c_duty_cycle_set(struct brcms_c_info *wlc, int duty_cycle, bool isOFDM,
        return 0;
 }
 
-/*
- * Initialize the base precedence map for dequeueing
- * from txq based on WME settings
- */
-static void brcms_c_tx_prec_map_init(struct brcms_c_info *wlc)
-{
-       wlc->tx_prec_map = BRCMS_PREC_BMP_ALL;
-       memset(wlc->fifo2prec_map, 0, NFIFO * sizeof(u16));
-
-       wlc->fifo2prec_map[TX_AC_BK_FIFO] = BRCMS_PREC_BMP_AC_BK;
-       wlc->fifo2prec_map[TX_AC_BE_FIFO] = BRCMS_PREC_BMP_AC_BE;
-       wlc->fifo2prec_map[TX_AC_VI_FIFO] = BRCMS_PREC_BMP_AC_VI;
-       wlc->fifo2prec_map[TX_AC_VO_FIFO] = BRCMS_PREC_BMP_AC_VO;
-}
-
-static void
-brcms_c_txflowcontrol_signal(struct brcms_c_info *wlc,
-                            struct brcms_txq_info *qi, bool on, int prio)
-{
-       /* transmit flowcontrol is not yet implemented */
-}
-
-static void brcms_c_txflowcontrol_reset(struct brcms_c_info *wlc)
-{
-       struct brcms_txq_info *qi;
-
-       for (qi = wlc->tx_queues; qi != NULL; qi = qi->next) {
-               if (qi->stopped) {
-                       brcms_c_txflowcontrol_signal(wlc, qi, OFF, ALLPRIO);
-                       qi->stopped = 0;
-               }
-       }
-}
-
 /* push sw hps and wake state through hardware */
 static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
 {
@@ -3795,7 +3761,8 @@ static void brcms_c_set_ps_ctrl(struct brcms_c_info *wlc)
 
        hps = brcms_c_ps_allowed(wlc);
 
-       BCMMSG(wlc->wiphy, "wl%d: hps %d\n", wlc->pub->unit, hps);
+       brcms_dbg_mac80211(wlc->hw->d11core, "wl%d: hps %d\n", wlc->pub->unit,
+                          hps);
 
        v1 = bcma_read32(wlc->hw->d11core, D11REGOFFS(maccontrol));
        v2 = MCTL_WAKE;
@@ -3881,7 +3848,8 @@ brcms_b_set_chanspec(struct brcms_hardware *wlc_hw, u16 chanspec,
 {
        uint bandunit;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d: 0x%x\n", wlc_hw->unit, chanspec);
+       brcms_dbg_mac80211(wlc_hw->d11core, "wl%d: 0x%x\n", wlc_hw->unit,
+                          chanspec);
 
        wlc_hw->chanspec = chanspec;
 
@@ -3942,7 +3910,7 @@ static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
        u16 old_chanspec = wlc->chanspec;
 
        if (!brcms_c_valid_chanspec_db(wlc->cmi, chanspec)) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: Bad channel %d\n",
+               brcms_err(wlc->hw->d11core, "wl%d: %s: Bad channel %d\n",
                          wlc->pub->unit, __func__, CHSPEC_CHANNEL(chanspec));
                return;
        }
@@ -3953,8 +3921,8 @@ static void brcms_c_set_chanspec(struct brcms_c_info *wlc, u16 chanspec)
                if (wlc->band->bandunit != bandunit || wlc->bandinit_pending) {
                        switchband = true;
                        if (wlc->bandlocked) {
-                               wiphy_err(wlc->wiphy, "wl%d: %s: chspec %d "
-                                         "band is locked!\n",
+                               brcms_err(wlc->hw->d11core,
+                                         "wl%d: %s: chspec %d band is locked!\n",
                                          wlc->pub->unit, __func__,
                                          CHSPEC_CHANNEL(chanspec));
                                return;
@@ -4018,6 +3986,10 @@ void brcms_c_beacon_phytxctl_txant_upd(struct brcms_c_info *wlc,
  */
 void brcms_c_protection_upd(struct brcms_c_info *wlc, uint idx, int val)
 {
+       /*
+        * Cannot use brcms_dbg_* here because this function is called
+        * before wlc is sufficiently initialized.
+        */
        BCMMSG(wlc->wiphy, "idx %d, val %d\n", idx, val);
 
        switch (idx) {
@@ -4090,8 +4062,8 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
 
        /* Only apply params if the core is out of reset and has clocks */
        if (!wlc->clk) {
-               wiphy_err(wlc->wiphy, "wl%d: %s : no-clock\n", wlc->pub->unit,
-                         __func__);
+               brcms_err(wlc->hw->d11core, "wl%d: %s : no-clock\n",
+                         wlc->pub->unit, __func__);
                return;
        }
 
@@ -4109,7 +4081,7 @@ void brcms_c_wme_setparams(struct brcms_c_info *wlc, u16 aci,
 
        if (acp_shm.aifs < EDCF_AIFSN_MIN
            || acp_shm.aifs > EDCF_AIFSN_MAX) {
-               wiphy_err(wlc->wiphy, "wl%d: edcf_setparams: bad "
+               brcms_err(wlc->hw->d11core, "wl%d: edcf_setparams: bad "
                          "aifs %d\n", wlc->pub->unit, acp_shm.aifs);
        } else {
                acp_shm.cwmin = params->cw_min;
@@ -4224,8 +4196,8 @@ static void brcms_c_radio_timer(void *arg)
        struct brcms_c_info *wlc = (struct brcms_c_info *) arg;
 
        if (brcms_deviceremoved(wlc)) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
-                       __func__);
+               brcms_err(wlc->hw->d11core, "wl%d: %s: dead chip\n",
+                         wlc->pub->unit, __func__);
                brcms_down(wlc->wl);
                return;
        }
@@ -4238,8 +4210,6 @@ static void brcms_b_watchdog(struct brcms_c_info *wlc)
 {
        struct brcms_hardware *wlc_hw = wlc->hw;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
        if (!wlc_hw->up)
                return;
 
@@ -4258,14 +4228,14 @@ static void brcms_b_watchdog(struct brcms_c_info *wlc)
 /* common watchdog code */
 static void brcms_c_watchdog(struct brcms_c_info *wlc)
 {
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+       brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);
 
        if (!wlc->pub->up)
                return;
 
        if (brcms_deviceremoved(wlc)) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: dead chip\n", wlc->pub->unit,
-                         __func__);
+               brcms_err(wlc->hw->d11core, "wl%d: %s: dead chip\n",
+                         wlc->pub->unit, __func__);
                brcms_down(wlc->wl);
                return;
        }
@@ -4437,13 +4407,13 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
        struct ssb_sprom *sprom = &core->bus->sprom;
 
        if (core->bus->hosttype == BCMA_HOSTTYPE_PCI)
-               BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
-                      pcidev->vendor,
-                      pcidev->device);
+               brcms_dbg_info(core, "wl%d: vendor 0x%x device 0x%x\n", unit,
+                              pcidev->vendor,
+                              pcidev->device);
        else
-               BCMMSG(wlc->wiphy, "wl%d: vendor 0x%x device 0x%x\n", unit,
-                      core->bus->boardinfo.vendor,
-                      core->bus->boardinfo.type);
+               brcms_dbg_info(core, "wl%d: vendor 0x%x device 0x%x\n", unit,
+                              core->bus->boardinfo.vendor,
+                              core->bus->boardinfo.type);
 
        wme = true;
 
@@ -4715,8 +4685,9 @@ static int brcms_b_attach(struct brcms_c_info *wlc, struct bcma_device *core,
                goto fail;
        }
 
-       BCMMSG(wlc->wiphy, "deviceid 0x%x nbands %d board 0x%x\n",
-              wlc_hw->deviceid, wlc_hw->_nbands, ai_get_boardtype(wlc_hw->sih));
+       brcms_dbg_info(wlc_hw->d11core, "deviceid 0x%x nbands %d board 0x%x\n",
+                      wlc_hw->deviceid, wlc_hw->_nbands,
+                      ai_get_boardtype(wlc_hw->sih));
 
        return err;
 
@@ -4836,56 +4807,6 @@ static void brcms_c_bss_default_init(struct brcms_c_info *wlc)
                bi->flags |= BRCMS_BSS_HT;
 }
 
-static struct brcms_txq_info *brcms_c_txq_alloc(struct brcms_c_info *wlc)
-{
-       struct brcms_txq_info *qi, *p;
-
-       qi = kzalloc(sizeof(struct brcms_txq_info), GFP_ATOMIC);
-       if (qi != NULL) {
-               /*
-                * Have enough room for control packets along with HI watermark
-                * Also, add room to txq for total psq packets if all the SCBs
-                * leave PS mode. The watermark for flowcontrol to OS packets
-                * will remain the same
-                */
-               brcmu_pktq_init(&qi->q, BRCMS_PREC_COUNT,
-                         2 * BRCMS_DATAHIWAT + PKTQ_LEN_DEFAULT);
-
-               /* add this queue to the the global list */
-               p = wlc->tx_queues;
-               if (p == NULL) {
-                       wlc->tx_queues = qi;
-               } else {
-                       while (p->next != NULL)
-                               p = p->next;
-                       p->next = qi;
-               }
-       }
-       return qi;
-}
-
-static void brcms_c_txq_free(struct brcms_c_info *wlc,
-                            struct brcms_txq_info *qi)
-{
-       struct brcms_txq_info *p;
-
-       if (qi == NULL)
-               return;
-
-       /* remove the queue from the linked list */
-       p = wlc->tx_queues;
-       if (p == qi)
-               wlc->tx_queues = p->next;
-       else {
-               while (p != NULL && p->next != qi)
-                       p = p->next;
-               if (p != NULL)
-                       p->next = p->next->next;
-       }
-
-       kfree(qi);
-}
-
 static void brcms_c_update_mimo_band_bwcap(struct brcms_c_info *wlc, u8 bwcap)
 {
        uint i;
@@ -4991,8 +4912,6 @@ uint brcms_c_detach(struct brcms_c_info *wlc)
        if (wlc == NULL)
                return 0;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
-
        callbacks += brcms_b_detach(wlc);
 
        /* delete software timers */
@@ -5005,10 +4924,6 @@ uint brcms_c_detach(struct brcms_c_info *wlc)
 
        brcms_c_detach_module(wlc);
 
-
-       while (wlc->tx_queues != NULL)
-               brcms_c_txq_free(wlc, wlc->tx_queues);
-
        brcms_c_detach_mfree(wlc);
        return callbacks;
 }
@@ -5026,7 +4941,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
        if (wlc_hw->wlc->pub->hw_up)
                return;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
 
        /*
         * Enable pll and xtal, initialize the power control registers,
@@ -5063,7 +4978,7 @@ static void brcms_b_hw_up(struct brcms_hardware *wlc_hw)
 
 static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
 {
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
+       brcms_dbg_info(wlc_hw->d11core, "wl%d\n", wlc_hw->unit);
 
        /*
         * Enable pll and xtal, initialize the power control registers,
@@ -5102,8 +5017,6 @@ static int brcms_b_up_prep(struct brcms_hardware *wlc_hw)
 
 static int brcms_b_up_finish(struct brcms_hardware *wlc_hw)
 {
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
        wlc_hw->up = true;
        wlc_phy_hw_state_upd(wlc_hw->band->pi, true);
 
@@ -5135,7 +5048,7 @@ int brcms_c_up(struct brcms_c_info *wlc)
 {
        struct ieee80211_channel *ch;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+       brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);
 
        /* HW is turned off so don't try to access it */
        if (wlc->pub->hw_off || brcms_deviceremoved(wlc))
@@ -5176,8 +5089,8 @@ int brcms_c_up(struct brcms_c_info *wlc)
                                         WL_RADIO_HW_DISABLE);
 
                                if (bsscfg->enable && bsscfg->BSS)
-                                       wiphy_err(wlc->wiphy, "wl%d: up"
-                                                 ": rfdisable -> "
+                                       brcms_err(wlc->hw->d11core,
+                                                 "wl%d: up: rfdisable -> "
                                                  "bsscfg_disable()\n",
                                                   wlc->pub->unit);
                        }
@@ -5237,8 +5150,6 @@ static int brcms_b_bmac_down_prep(struct brcms_hardware *wlc_hw)
        bool dev_gone;
        uint callbacks = 0;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
        if (!wlc_hw->up)
                return callbacks;
 
@@ -5265,8 +5176,6 @@ static int brcms_b_down_finish(struct brcms_hardware *wlc_hw)
        uint callbacks = 0;
        bool dev_gone;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
-
        if (!wlc_hw->up)
                return callbacks;
 
@@ -5314,14 +5223,14 @@ uint brcms_c_down(struct brcms_c_info *wlc)
        uint callbacks = 0;
        int i;
        bool dev_gone = false;
-       struct brcms_txq_info *qi;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+       brcms_dbg_info(wlc->hw->d11core, "wl%d\n", wlc->pub->unit);
 
        /* check if we are already in the going down path */
        if (wlc->going_down) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: Driver going down so return"
-                         "\n", wlc->pub->unit, __func__);
+               brcms_err(wlc->hw->d11core,
+                         "wl%d: %s: Driver going down so return\n",
+                         wlc->pub->unit, __func__);
                return 0;
        }
        if (!wlc->pub->up)
@@ -5353,13 +5262,6 @@ uint brcms_c_down(struct brcms_c_info *wlc)
 
        wlc_phy_mute_upd(wlc->band->pi, false, PHY_MUTE_ALL);
 
-       /* clear txq flow control */
-       brcms_c_txflowcontrol_reset(wlc);
-
-       /* flush tx queues */
-       for (qi = wlc->tx_queues; qi != NULL; qi = qi->next)
-               brcmu_pktq_flush(&qi->q, true, NULL, NULL);
-
        callbacks += brcms_b_down_finish(wlc->hw);
 
        /* brcms_b_down_finish has done brcms_c_coredisable(). so clk is off */
@@ -5441,7 +5343,7 @@ int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config)
 
        default:
                /* Error */
-               wiphy_err(wlc->wiphy, "wl%d: %s: invalid gmode %d\n",
+               brcms_err(wlc->hw->d11core, "wl%d: %s: invalid gmode %d\n",
                          wlc->pub->unit, __func__, gmode);
                return -ENOTSUPP;
        }
@@ -5745,45 +5647,6 @@ int brcms_c_module_unregister(struct brcms_pub *pub, const char *name,
        return -ENODATA;
 }
 
-void brcms_c_print_txstatus(struct tx_status *txs)
-{
-       pr_debug("\ntxpkt (MPDU) Complete\n");
-
-       pr_debug("FrameID: %04x   TxStatus: %04x\n", txs->frameid, txs->status);
-
-       pr_debug("[15:12]  %d  frame attempts\n",
-                 (txs->status & TX_STATUS_FRM_RTX_MASK) >>
-                TX_STATUS_FRM_RTX_SHIFT);
-       pr_debug(" [11:8]  %d  rts attempts\n",
-                (txs->status & TX_STATUS_RTS_RTX_MASK) >>
-                TX_STATUS_RTS_RTX_SHIFT);
-       pr_debug("    [7]  %d  PM mode indicated\n",
-                txs->status & TX_STATUS_PMINDCTD ? 1 : 0);
-       pr_debug("    [6]  %d  intermediate status\n",
-                txs->status & TX_STATUS_INTERMEDIATE ? 1 : 0);
-       pr_debug("    [5]  %d  AMPDU\n",
-                txs->status & TX_STATUS_AMPDU ? 1 : 0);
-       pr_debug("  [4:2]  %d  Frame Suppressed Reason (%s)\n",
-                (txs->status & TX_STATUS_SUPR_MASK) >> TX_STATUS_SUPR_SHIFT,
-                (const char *[]) {
-                       "None",
-                       "PMQ Entry",
-                       "Flush request",
-                       "Previous frag failure",
-                       "Channel mismatch",
-                       "Lifetime Expiry",
-                       "Underflow"
-                } [(txs->status & TX_STATUS_SUPR_MASK) >>
-                   TX_STATUS_SUPR_SHIFT]);
-       pr_debug("    [1]  %d  acked\n",
-                txs->status & TX_STATUS_ACK_RCV ? 1 : 0);
-
-       pr_debug("LastTxTime: %04x Seq: %04x PHYTxStatus: %04x RxAckRSSI: %04x RxAckSQ: %04x\n",
-                txs->lasttxtime, txs->sequence, txs->phyerr,
-                (txs->ackphyrxsh & PRXS1_JSSI_MASK) >> PRXS1_JSSI_SHIFT,
-                (txs->ackphyrxsh & PRXS1_SQ_MASK) >> PRXS1_SQ_SHIFT);
-}
-
 static bool brcms_c_chipmatch_pci(struct bcma_device *core)
 {
        struct pci_dev *pcidev = core->bus->host_pci;
@@ -5832,184 +5695,6 @@ bool brcms_c_chipmatch(struct bcma_device *core)
        }
 }
 
-#if defined(DEBUG)
-void brcms_c_print_txdesc(struct d11txh *txh)
-{
-       u16 mtcl = le16_to_cpu(txh->MacTxControlLow);
-       u16 mtch = le16_to_cpu(txh->MacTxControlHigh);
-       u16 mfc = le16_to_cpu(txh->MacFrameControl);
-       u16 tfest = le16_to_cpu(txh->TxFesTimeNormal);
-       u16 ptcw = le16_to_cpu(txh->PhyTxControlWord);
-       u16 ptcw_1 = le16_to_cpu(txh->PhyTxControlWord_1);
-       u16 ptcw_1_Fbr = le16_to_cpu(txh->PhyTxControlWord_1_Fbr);
-       u16 ptcw_1_Rts = le16_to_cpu(txh->PhyTxControlWord_1_Rts);
-       u16 ptcw_1_FbrRts = le16_to_cpu(txh->PhyTxControlWord_1_FbrRts);
-       u16 mainrates = le16_to_cpu(txh->MainRates);
-       u16 xtraft = le16_to_cpu(txh->XtraFrameTypes);
-       u8 *iv = txh->IV;
-       u8 *ra = txh->TxFrameRA;
-       u16 tfestfb = le16_to_cpu(txh->TxFesTimeFallback);
-       u8 *rtspfb = txh->RTSPLCPFallback;
-       u16 rtsdfb = le16_to_cpu(txh->RTSDurFallback);
-       u8 *fragpfb = txh->FragPLCPFallback;
-       u16 fragdfb = le16_to_cpu(txh->FragDurFallback);
-       u16 mmodelen = le16_to_cpu(txh->MModeLen);
-       u16 mmodefbrlen = le16_to_cpu(txh->MModeFbrLen);
-       u16 tfid = le16_to_cpu(txh->TxFrameID);
-       u16 txs = le16_to_cpu(txh->TxStatus);
-       u16 mnmpdu = le16_to_cpu(txh->MaxNMpdus);
-       u16 mabyte = le16_to_cpu(txh->MaxABytes_MRT);
-       u16 mabyte_f = le16_to_cpu(txh->MaxABytes_FBR);
-       u16 mmbyte = le16_to_cpu(txh->MinMBytes);
-
-       u8 *rtsph = txh->RTSPhyHeader;
-       struct ieee80211_rts rts = txh->rts_frame;
-
-       /* add plcp header along with txh descriptor */
-       brcmu_dbg_hex_dump(txh, sizeof(struct d11txh) + 48,
-                          "Raw TxDesc + plcp header:\n");
-
-       pr_debug("TxCtlLow: %04x ", mtcl);
-       pr_debug("TxCtlHigh: %04x ", mtch);
-       pr_debug("FC: %04x ", mfc);
-       pr_debug("FES Time: %04x\n", tfest);
-       pr_debug("PhyCtl: %04x%s ", ptcw,
-              (ptcw & PHY_TXC_SHORT_HDR) ? " short" : "");
-       pr_debug("PhyCtl_1: %04x ", ptcw_1);
-       pr_debug("PhyCtl_1_Fbr: %04x\n", ptcw_1_Fbr);
-       pr_debug("PhyCtl_1_Rts: %04x ", ptcw_1_Rts);
-       pr_debug("PhyCtl_1_Fbr_Rts: %04x\n", ptcw_1_FbrRts);
-       pr_debug("MainRates: %04x ", mainrates);
-       pr_debug("XtraFrameTypes: %04x ", xtraft);
-       pr_debug("\n");
-
-       print_hex_dump_bytes("SecIV:", DUMP_PREFIX_OFFSET, iv, sizeof(txh->IV));
-       print_hex_dump_bytes("RA:", DUMP_PREFIX_OFFSET,
-                            ra, sizeof(txh->TxFrameRA));
-
-       pr_debug("Fb FES Time: %04x ", tfestfb);
-       print_hex_dump_bytes("Fb RTS PLCP:", DUMP_PREFIX_OFFSET,
-                            rtspfb, sizeof(txh->RTSPLCPFallback));
-       pr_debug("RTS DUR: %04x ", rtsdfb);
-       print_hex_dump_bytes("PLCP:", DUMP_PREFIX_OFFSET,
-                            fragpfb, sizeof(txh->FragPLCPFallback));
-       pr_debug("DUR: %04x", fragdfb);
-       pr_debug("\n");
-
-       pr_debug("MModeLen: %04x ", mmodelen);
-       pr_debug("MModeFbrLen: %04x\n", mmodefbrlen);
-
-       pr_debug("FrameID:     %04x\n", tfid);
-       pr_debug("TxStatus:    %04x\n", txs);
-
-       pr_debug("MaxNumMpdu:  %04x\n", mnmpdu);
-       pr_debug("MaxAggbyte:  %04x\n", mabyte);
-       pr_debug("MaxAggbyte_fb:  %04x\n", mabyte_f);
-       pr_debug("MinByte:     %04x\n", mmbyte);
-
-       print_hex_dump_bytes("RTS PLCP:", DUMP_PREFIX_OFFSET,
-                            rtsph, sizeof(txh->RTSPhyHeader));
-       print_hex_dump_bytes("RTS Frame:", DUMP_PREFIX_OFFSET,
-                            (u8 *)&rts, sizeof(txh->rts_frame));
-       pr_debug("\n");
-}
-#endif                         /* defined(DEBUG) */
-
-#if defined(DEBUG)
-static int
-brcms_c_format_flags(const struct brcms_c_bit_desc *bd, u32 flags, char *buf,
-                    int len)
-{
-       int i;
-       char *p = buf;
-       char hexstr[16];
-       int slen = 0, nlen = 0;
-       u32 bit;
-       const char *name;
-
-       if (len < 2 || !buf)
-               return 0;
-
-       buf[0] = '\0';
-
-       for (i = 0; flags != 0; i++) {
-               bit = bd[i].bit;
-               name = bd[i].name;
-               if (bit == 0 && flags != 0) {
-                       /* print any unnamed bits */
-                       snprintf(hexstr, 16, "0x%X", flags);
-                       name = hexstr;
-                       flags = 0;      /* exit loop */
-               } else if ((flags & bit) == 0)
-                       continue;
-               flags &= ~bit;
-               nlen = strlen(name);
-               slen += nlen;
-               /* count btwn flag space */
-               if (flags != 0)
-                       slen += 1;
-               /* need NULL char as well */
-               if (len <= slen)
-                       break;
-               /* copy NULL char but don't count it */
-               strncpy(p, name, nlen + 1);
-               p += nlen;
-               /* copy btwn flag space and NULL char */
-               if (flags != 0)
-                       p += snprintf(p, 2, " ");
-               len -= slen;
-       }
-
-       /* indicate the str was too short */
-       if (flags != 0) {
-               if (len < 2)
-                       p -= 2 - len;   /* overwrite last char */
-               p += snprintf(p, 2, ">");
-       }
-
-       return (int)(p - buf);
-}
-#endif                         /* defined(DEBUG) */
-
-#if defined(DEBUG)
-void brcms_c_print_rxh(struct d11rxhdr *rxh)
-{
-       u16 len = rxh->RxFrameSize;
-       u16 phystatus_0 = rxh->PhyRxStatus_0;
-       u16 phystatus_1 = rxh->PhyRxStatus_1;
-       u16 phystatus_2 = rxh->PhyRxStatus_2;
-       u16 phystatus_3 = rxh->PhyRxStatus_3;
-       u16 macstatus1 = rxh->RxStatus1;
-       u16 macstatus2 = rxh->RxStatus2;
-       char flagstr[64];
-       char lenbuf[20];
-       static const struct brcms_c_bit_desc macstat_flags[] = {
-               {RXS_FCSERR, "FCSErr"},
-               {RXS_RESPFRAMETX, "Reply"},
-               {RXS_PBPRES, "PADDING"},
-               {RXS_DECATMPT, "DeCr"},
-               {RXS_DECERR, "DeCrErr"},
-               {RXS_BCNSENT, "Bcn"},
-               {0, NULL}
-       };
-
-       brcmu_dbg_hex_dump(rxh, sizeof(struct d11rxhdr), "Raw RxDesc:\n");
-
-       brcms_c_format_flags(macstat_flags, macstatus1, flagstr, 64);
-
-       snprintf(lenbuf, sizeof(lenbuf), "0x%x", len);
-
-       pr_debug("RxFrameSize:     %6s (%d)%s\n", lenbuf, len,
-              (rxh->PhyRxStatus_0 & PRXS0_SHORTH) ? " short preamble" : "");
-       pr_debug("RxPHYStatus:     %04x %04x %04x %04x\n",
-              phystatus_0, phystatus_1, phystatus_2, phystatus_3);
-       pr_debug("RxMACStatus:     %x %s\n", macstatus1, flagstr);
-       pr_debug("RXMACaggtype:    %x\n",
-              (macstatus2 & RXS_AGGTYPE_MASK));
-       pr_debug("RxTSFTime:       %04x\n", rxh->RxTSFTime);
-}
-#endif                         /* defined(DEBUG) */
-
 u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
 {
        u16 table_ptr;
@@ -6033,86 +5718,6 @@ u16 brcms_b_rate_shm_offset(struct brcms_hardware *wlc_hw, u8 rate)
        return 2 * brcms_b_read_shm(wlc_hw, table_ptr + (index * 2));
 }
 
-static bool
-brcms_c_prec_enq_head(struct brcms_c_info *wlc, struct pktq *q,
-                     struct sk_buff *pkt, int prec, bool head)
-{
-       struct sk_buff *p;
-       int eprec = -1;         /* precedence to evict from */
-
-       /* Determine precedence from which to evict packet, if any */
-       if (pktq_pfull(q, prec))
-               eprec = prec;
-       else if (pktq_full(q)) {
-               p = brcmu_pktq_peek_tail(q, &eprec);
-               if (eprec > prec) {
-                       wiphy_err(wlc->wiphy, "%s: Failing: eprec %d > prec %d"
-                                 "\n", __func__, eprec, prec);
-                       return false;
-               }
-       }
-
-       /* Evict if needed */
-       if (eprec >= 0) {
-               bool discard_oldest;
-
-               discard_oldest = ac_bitmap_tst(0, eprec);
-
-               /* Refuse newer packet unless configured to discard oldest */
-               if (eprec == prec && !discard_oldest) {
-                       wiphy_err(wlc->wiphy, "%s: No where to go, prec == %d"
-                                 "\n", __func__, prec);
-                       return false;
-               }
-
-               /* Evict packet according to discard policy */
-               p = discard_oldest ? brcmu_pktq_pdeq(q, eprec) :
-                       brcmu_pktq_pdeq_tail(q, eprec);
-               brcmu_pkt_buf_free_skb(p);
-       }
-
-       /* Enqueue */
-       if (head)
-               p = brcmu_pktq_penq_head(q, prec, pkt);
-       else
-               p = brcmu_pktq_penq(q, prec, pkt);
-
-       return true;
-}
-
-/*
- * Attempts to queue a packet onto a multiple-precedence queue,
- * if necessary evicting a lower precedence packet from the queue.
- *
- * 'prec' is the precedence number that has already been mapped
- * from the packet priority.
- *
- * Returns true if packet consumed (queued), false if not.
- */
-static bool brcms_c_prec_enq(struct brcms_c_info *wlc, struct pktq *q,
-                     struct sk_buff *pkt, int prec)
-{
-       return brcms_c_prec_enq_head(wlc, q, pkt, prec, false);
-}
-
-void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
-                    struct sk_buff *sdu, uint prec)
-{
-       struct brcms_txq_info *qi = wlc->pkt_queue;     /* Check me */
-       struct pktq *q = &qi->q;
-       int prio;
-
-       prio = sdu->priority;
-
-       if (!brcms_c_prec_enq(wlc, q, sdu, prec)) {
-               /*
-                * we might hit this condtion in case
-                * packet flooding from mac80211 stack
-                */
-               brcmu_pkt_buf_free_skb(sdu);
-       }
-}
-
 /*
  * bcmc_fid_generate:
  * Generate frame ID for a BCMC packet.  The frag field is not used
@@ -6140,8 +5745,6 @@ brcms_c_calc_ack_time(struct brcms_c_info *wlc, u32 rspec,
 {
        uint dur = 0;
 
-       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d\n",
-               wlc->pub->unit, rspec, preamble_type);
        /*
         * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
         * is less than or equal to the rate of the immediately previous
@@ -6159,8 +5762,6 @@ static uint
 brcms_c_calc_cts_time(struct brcms_c_info *wlc, u32 rspec,
                      u8 preamble_type)
 {
-       BCMMSG(wlc->wiphy, "wl%d: ratespec 0x%x, preamble_type %d\n",
-               wlc->pub->unit, rspec, preamble_type);
        return brcms_c_calc_ack_time(wlc, rspec, preamble_type);
 }
 
@@ -6168,8 +5769,6 @@ static uint
 brcms_c_calc_ba_time(struct brcms_c_info *wlc, u32 rspec,
                     u8 preamble_type)
 {
-       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, "
-                "preamble_type %d\n", wlc->pub->unit, rspec, preamble_type);
        /*
         * Spec 9.6: ack rate is the highest rate in BSSBasicRateSet that
         * is less than or equal to the rate of the immediately previous
@@ -6223,9 +5822,6 @@ brcms_c_calc_frame_len(struct brcms_c_info *wlc, u32 ratespec,
        uint nsyms, mac_len, Ndps, kNdps;
        uint rate = rspec2rate(ratespec);
 
-       BCMMSG(wlc->wiphy, "wl%d: rspec 0x%x, preamble_type %d, dur %d\n",
-                wlc->pub->unit, ratespec, preamble_type, dur);
-
        if (is_mcs_rate(ratespec)) {
                uint mcs = ratespec & RSPEC_RATE_MASK;
                int tot_streams = mcs_2_txstreams(mcs) + rspec_stc(ratespec);
@@ -6292,7 +5888,7 @@ static bool brcms_c_valid_rate(struct brcms_c_info *wlc, u32 rspec, int band,
                        return true;
  error:
        if (verbose)
-               wiphy_err(wlc->wiphy, "wl%d: valid_rate: rate spec 0x%x "
+               brcms_err(wlc->hw->d11core, "wl%d: valid_rate: rate spec 0x%x "
                          "not in hw_rateset\n", wlc->pub->unit, rspec);
 
        return false;
@@ -6302,6 +5898,7 @@ static u32
 mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
                       u32 int_val)
 {
+       struct bcma_device *core = wlc->hw->d11core;
        u8 stf = (int_val & NRATE_STF_MASK) >> NRATE_STF_SHIFT;
        u8 rate = int_val & NRATE_RATE_MASK;
        u32 rspec;
@@ -6318,7 +5915,7 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
        if ((wlc->pub->_n_enab & SUPPORT_11N) && ismcs) {
                /* mcs only allowed when nmode */
                if (stf > PHY_TXC1_MODE_SDM) {
-                       wiphy_err(wlc->wiphy, "wl%d: %s: Invalid stf\n",
+                       brcms_err(core, "wl%d: %s: Invalid stf\n",
                                  wlc->pub->unit, __func__);
                        bcmerror = -EINVAL;
                        goto done;
@@ -6329,8 +5926,8 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
                        if (!CHSPEC_IS40(wlc->home_chanspec) ||
                            ((stf != PHY_TXC1_MODE_SISO)
                             && (stf != PHY_TXC1_MODE_CDD))) {
-                               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid mcs "
-                                         "32\n", wlc->pub->unit, __func__);
+                               brcms_err(core, "wl%d: %s: Invalid mcs 32\n",
+                                         wlc->pub->unit, __func__);
                                bcmerror = -EINVAL;
                                goto done;
                        }
@@ -6338,9 +5935,9 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
                } else if (rate > HIGHEST_SINGLE_STREAM_MCS) {
                        /* mcs > 7 must use stf SDM */
                        if (stf != PHY_TXC1_MODE_SDM) {
-                               BCMMSG(wlc->wiphy, "wl%d: enabling "
-                                      "SDM mode for mcs %d\n",
-                                      wlc->pub->unit, rate);
+                               brcms_dbg_mac80211(core, "wl%d: enabling "
+                                                  "SDM mode for mcs %d\n",
+                                                  wlc->pub->unit, rate);
                                stf = PHY_TXC1_MODE_SDM;
                        }
                } else {
@@ -6351,15 +5948,15 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
                        if ((stf > PHY_TXC1_MODE_STBC) ||
                            (!BRCMS_STBC_CAP_PHY(wlc)
                             && (stf == PHY_TXC1_MODE_STBC))) {
-                               wiphy_err(wlc->wiphy, "wl%d: %s: Invalid STBC"
-                                         "\n", wlc->pub->unit, __func__);
+                               brcms_err(core, "wl%d: %s: Invalid STBC\n",
+                                         wlc->pub->unit, __func__);
                                bcmerror = -EINVAL;
                                goto done;
                        }
                }
        } else if (is_ofdm_rate(rate)) {
                if ((stf != PHY_TXC1_MODE_CDD) && (stf != PHY_TXC1_MODE_SISO)) {
-                       wiphy_err(wlc->wiphy, "wl%d: %s: Invalid OFDM\n",
+                       brcms_err(core, "wl%d: %s: Invalid OFDM\n",
                                  wlc->pub->unit, __func__);
                        bcmerror = -EINVAL;
                        goto done;
@@ -6367,20 +5964,20 @@ mac80211_wlc_set_nrate(struct brcms_c_info *wlc, struct brcms_band *cur_band,
        } else if (is_cck_rate(rate)) {
                if ((cur_band->bandtype != BRCM_BAND_2G)
                    || (stf != PHY_TXC1_MODE_SISO)) {
-                       wiphy_err(wlc->wiphy, "wl%d: %s: Invalid CCK\n",
+                       brcms_err(core, "wl%d: %s: Invalid CCK\n",
                                  wlc->pub->unit, __func__);
                        bcmerror = -EINVAL;
                        goto done;
                }
        } else {
-               wiphy_err(wlc->wiphy, "wl%d: %s: Unknown rate type\n",
+               brcms_err(core, "wl%d: %s: Unknown rate type\n",
                          wlc->pub->unit, __func__);
                bcmerror = -EINVAL;
                goto done;
        }
        /* make sure multiple antennae are available for non-siso rates */
        if ((stf != PHY_TXC1_MODE_SISO) && (wlc->stf->txstreams == 1)) {
-               wiphy_err(wlc->wiphy, "wl%d: %s: SISO antenna but !SISO "
+               brcms_err(core, "wl%d: %s: SISO antenna but !SISO "
                          "request\n", wlc->pub->unit, __func__);
                bcmerror = -EINVAL;
                goto done;
@@ -6449,7 +6046,7 @@ static void brcms_c_cck_plcp_set(struct brcms_c_info *wlc, int rate_500,
                break;
 
        default:
-               wiphy_err(wlc->wiphy,
+               brcms_err(wlc->hw->d11core,
                          "brcms_c_cck_plcp_set: unsupported rate %d\n",
                          rate_500);
                rate_500 = BRCM_RATE_1M;
@@ -6582,7 +6179,7 @@ static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
                bw = rspec_get_bw(rspec);
                /* 10Mhz is not supported yet */
                if (bw < PHY_TXC1_BW_20MHZ) {
-                       wiphy_err(wlc->wiphy, "phytxctl1_calc: bw %d is "
+                       brcms_err(wlc->hw->d11core, "phytxctl1_calc: bw %d is "
                                  "not supported yet, set to 20L\n", bw);
                        bw = PHY_TXC1_BW_20MHZ;
                }
@@ -6609,7 +6206,7 @@ static u16 brcms_c_phytxctl1_calc(struct brcms_c_info *wlc, u32 rspec)
                /* get the phyctl byte from rate phycfg table */
                phycfg = brcms_c_rate_legacy_phyctl(rspec2rate(rspec));
                if (phycfg == -1) {
-                       wiphy_err(wlc->wiphy, "phytxctl1_calc: wrong "
+                       brcms_err(wlc->hw->d11core, "phytxctl1_calc: wrong "
                                  "legacy OFDM/CCK rate\n");
                        phycfg = 0;
                }
@@ -6689,8 +6286,9 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
        if (tx_info->flags & IEEE80211_TX_CTL_ASSIGN_SEQ) {
                /* non-AP STA should never use BCMC queue */
                if (queue == TX_BCMC_FIFO) {
-                       wiphy_err(wlc->wiphy, "wl%d: %s: ASSERT queue == "
-                                 "TX_BCMC!\n", wlc->pub->unit, __func__);
+                       brcms_err(wlc->hw->d11core,
+                                 "wl%d: %s: ASSERT queue == TX_BCMC!\n",
+                                 wlc->pub->unit, __func__);
                        frameid = bcmc_fid_generate(wlc, NULL, txh);
                } else {
                        /* Increment the counter for first fragment */
@@ -6860,7 +6458,8 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
 
                        if ((txrate[k]->flags & IEEE80211_TX_RC_MCS)
                            && (!is_mcs_rate(rspec[k]))) {
-                               wiphy_err(wlc->wiphy, "wl%d: %s: IEEE80211_TX_"
+                               brcms_err(wlc->hw->d11core,
+                                         "wl%d: %s: IEEE80211_TX_"
                                          "RC_MCS != is_mcs_rate(rspec)\n",
                                          wlc->pub->unit, __func__);
                        }
@@ -7254,14 +6853,16 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
                                        wlc->fragthresh[queue] =
                                            (u16) newfragthresh;
                        } else {
-                               wiphy_err(wlc->wiphy, "wl%d: %s txop invalid "
+                               brcms_err(wlc->hw->d11core,
+                                         "wl%d: %s txop invalid "
                                          "for rate %d\n",
                                          wlc->pub->unit, fifo_names[queue],
                                          rspec2rate(rspec[0]));
                        }
 
                        if (dur > wlc->edcf_txop[ac])
-                               wiphy_err(wlc->wiphy, "wl%d: %s: %s txop "
+                               brcms_err(wlc->hw->d11core,
+                                         "wl%d: %s: %s txop "
                                          "exceeded phylen %d/%d dur %d/%d\n",
                                          wlc->pub->unit, __func__,
                                          fifo_names[queue],
@@ -7273,79 +6874,33 @@ brcms_c_d11hdrs_mac80211(struct brcms_c_info *wlc, struct ieee80211_hw *hw,
        return 0;
 }
 
-void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,
-                             struct ieee80211_hw *hw)
+static int brcms_c_tx(struct brcms_c_info *wlc, struct sk_buff *skb)
 {
-       u8 prio;
-       uint fifo;
-       struct scb *scb = &wlc->pri_scb;
-       struct ieee80211_hdr *d11_header = (struct ieee80211_hdr *)(sdu->data);
-
-       /*
-        * 802.11 standard requires management traffic
-        * to go at highest priority
-        */
-       prio = ieee80211_is_data(d11_header->frame_control) ? sdu->priority :
-               MAXPRIO;
-       fifo = prio2fifo[prio];
-       if (brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0))
-               return;
-       brcms_c_txq_enq(wlc, scb, sdu, BRCMS_PRIO_TO_PREC(prio));
-       brcms_c_send_q(wlc);
-}
-
-void brcms_c_send_q(struct brcms_c_info *wlc)
-{
-       struct sk_buff *pkt[DOT11_MAXNUMFRAGS];
-       int prec;
-       u16 prec_map;
-       int err = 0, i, count;
-       uint fifo;
-       struct brcms_txq_info *qi = wlc->pkt_queue;
-       struct pktq *q = &qi->q;
-       struct ieee80211_tx_info *tx_info;
-
-       prec_map = wlc->tx_prec_map;
+       struct dma_pub *dma;
+       int fifo, ret = -ENOSPC;
+       struct d11txh *txh;
+       u16 frameid = INVALIDFID;
 
-       /* Send all the enq'd pkts that we can.
-        * Dequeue packets with precedence with empty HW fifo only
-        */
-       while (prec_map && (pkt[0] = brcmu_pktq_mdeq(q, prec_map, &prec))) {
-               tx_info = IEEE80211_SKB_CB(pkt[0]);
-               if (tx_info->flags & IEEE80211_TX_CTL_AMPDU) {
-                       err = brcms_c_sendampdu(wlc->ampdu, qi, pkt, prec);
-               } else {
-                       count = 1;
-                       err = brcms_c_prep_pdu(wlc, pkt[0], &fifo);
-                       if (!err) {
-                               for (i = 0; i < count; i++)
-                                       brcms_c_txfifo(wlc, fifo, pkt[i], true,
-                                                      1);
-                       }
-               }
+       fifo = brcms_ac_to_fifo(skb_get_queue_mapping(skb));
+       dma = wlc->hw->di[fifo];
+       txh = (struct d11txh *)(skb->data);
 
-               if (err == -EBUSY) {
-                       brcmu_pktq_penq_head(q, prec, pkt[0]);
-                       /*
-                        * If send failed due to any other reason than a
-                        * change in HW FIFO condition, quit. Otherwise,
-                        * read the new prec_map!
-                        */
-                       if (prec_map == wlc->tx_prec_map)
-                               break;
-                       prec_map = wlc->tx_prec_map;
-               }
+       if (dma->txavail == 0) {
+               /*
+                * We sometimes get a frame from mac80211 after stopping
+                * the queues. This only ever seems to be a single frame
+                * and is seems likely to be a race. TX_HEADROOM should
+                * ensure that we have enough space to handle these stray
+                * packets, so warn if there isn't. If we're out of space
+                * in the tx ring and the tx queue isn't stopped then
+                * we've really got a bug; warn loudly if that happens.
+                */
+               brcms_warn(wlc->hw->d11core,
+                          "Received frame for tx with no space in DMA ring\n");
+               WARN_ON(!ieee80211_queue_stopped(wlc->pub->ieee_hw,
+                                                skb_get_queue_mapping(skb)));
+               return -ENOSPC;
        }
-}
-
-void
-brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
-              bool commit, s8 txpktpend)
-{
-       u16 frameid = INVALIDFID;
-       struct d11txh *txh;
-
-       txh = (struct d11txh *) (p->data);
 
        /* When a BC/MC frame is being committed to the BCMC fifo
         * via DMA (NOT PIO), update ucode or BSS info as appropriate.
@@ -7353,16 +6908,6 @@ brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
        if (fifo == TX_BCMC_FIFO)
                frameid = le16_to_cpu(txh->TxFrameID);
 
-       /*
-        * Bump up pending count for if not using rpc. If rpc is
-        * used, this will be handled in brcms_b_txfifo()
-        */
-       if (commit) {
-               wlc->core->txpktpend[fifo] += txpktpend;
-               BCMMSG(wlc->wiphy, "pktpend inc %d to %d\n",
-                        txpktpend, wlc->core->txpktpend[fifo]);
-       }
-
        /* Commit BCMC sequence number in the SHM frame ID location */
        if (frameid != INVALIDFID) {
                /*
@@ -7372,8 +6917,52 @@ brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p,
                brcms_b_write_shm(wlc->hw, M_BCMC_FID, frameid);
        }
 
-       if (dma_txfast(wlc->hw->di[fifo], p, commit) < 0)
+       ret = brcms_c_txfifo(wlc, fifo, skb);
+       /*
+        * The only reason for brcms_c_txfifo to fail is because
+        * there weren't any DMA descriptors, but we've already
+        * checked for that. So if it does fail yell loudly.
+        */
+       WARN_ON_ONCE(ret);
+
+       return ret;
+}
+
+void brcms_c_sendpkt_mac80211(struct brcms_c_info *wlc, struct sk_buff *sdu,
+                             struct ieee80211_hw *hw)
+{
+       uint fifo;
+       struct scb *scb = &wlc->pri_scb;
+
+       fifo = brcms_ac_to_fifo(skb_get_queue_mapping(sdu));
+       if (brcms_c_d11hdrs_mac80211(wlc, hw, sdu, scb, 0, 1, fifo, 0))
+               return;
+       if (brcms_c_tx(wlc, sdu))
+               dev_kfree_skb_any(sdu);
+}
+
+int
+brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo, struct sk_buff *p)
+{
+       struct dma_pub *dma = wlc->hw->di[fifo];
+       int ret;
+       u16 queue;
+
+       ret = dma_txfast(wlc, dma, p);
+       if (ret < 0)
                wiphy_err(wlc->wiphy, "txfifo: fatal, toss frames !!!\n");
+
+       /*
+        * Stop queue if DMA ring is full. Reserve some free descriptors,
+        * as we sometimes receive a frame from mac80211 after the queues
+        * are stopped.
+        */
+       queue = skb_get_queue_mapping(p);
+       if (dma->txavail <= TX_HEADROOM && fifo < TX_BCMC_FIFO &&
+           !ieee80211_queue_stopped(wlc->pub->ieee_hw, queue))
+               ieee80211_stop_queue(wlc->pub->ieee_hw, queue);
+
+       return ret;
 }
 
 u32
@@ -7423,19 +7012,6 @@ brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc, u32 rspec,
        return rts_rspec;
 }
 
-void
-brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo, s8 txpktpend)
-{
-       wlc->core->txpktpend[fifo] -= txpktpend;
-       BCMMSG(wlc->wiphy, "pktpend dec %d to %d\n", txpktpend,
-              wlc->core->txpktpend[fifo]);
-
-       /* There is more room; mark precedences related to this FIFO sendable */
-       wlc->tx_prec_map |= wlc->fifo2prec_map[fifo];
-
-       /* figure out which bsscfg is being worked on... */
-}
-
 /* Update beacon listen interval in shared memory */
 static void brcms_c_bcn_li_upd(struct brcms_c_info *wlc)
 {
@@ -7508,7 +7084,7 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
 
        /* fill in TSF and flag its presence */
        rx_status->mactime = brcms_c_recover_tsf64(wlc, rxh);
-       rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+       rx_status->flag |= RX_FLAG_MACTIME_START;
 
        channel = BRCMS_CHAN_CHANNEL(rxh->RxChan);
 
@@ -7571,7 +7147,8 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
                        rx_status->rate_idx = 11;
                        break;
                default:
-                       wiphy_err(wlc->wiphy, "%s: Unknown rate\n", __func__);
+                       brcms_err(wlc->hw->d11core,
+                                 "%s: Unknown rate\n", __func__);
                }
 
                /*
@@ -7590,7 +7167,7 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
                } else if (is_ofdm_rate(rspec)) {
                        rx_status->flag |= RX_FLAG_SHORTPRE;
                } else {
-                       wiphy_err(wlc->wiphy, "%s: Unknown modulation\n",
+                       brcms_err(wlc->hw->d11core, "%s: Unknown modulation\n",
                                  __func__);
                }
        }
@@ -7600,12 +7177,12 @@ prep_mac80211_status(struct brcms_c_info *wlc, struct d11rxhdr *rxh,
 
        if (rxh->RxStatus1 & RXS_DECERR) {
                rx_status->flag |= RX_FLAG_FAILED_PLCP_CRC;
-               wiphy_err(wlc->wiphy, "%s:  RX_FLAG_FAILED_PLCP_CRC\n",
+               brcms_err(wlc->hw->d11core, "%s:  RX_FLAG_FAILED_PLCP_CRC\n",
                          __func__);
        }
        if (rxh->RxStatus1 & RXS_FCSERR) {
                rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
-               wiphy_err(wlc->wiphy, "%s:  RX_FLAG_FAILED_FCS_CRC\n",
+               brcms_err(wlc->hw->d11core, "%s:  RX_FLAG_FAILED_FCS_CRC\n",
                          __func__);
        }
 }
@@ -7649,9 +7226,6 @@ brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
 {
        uint nsyms, len = 0, kNdps;
 
-       BCMMSG(wlc->wiphy, "wl%d: rate %d, len%d\n",
-                wlc->pub->unit, rspec2rate(ratespec), mac_len);
-
        if (is_mcs_rate(ratespec)) {
                uint mcs = ratespec & RSPEC_RATE_MASK;
                int tot_streams = (mcs_2_txstreams(mcs) + 1) +
@@ -7883,35 +7457,6 @@ void brcms_c_update_probe_resp(struct brcms_c_info *wlc, bool suspend)
                brcms_c_bss_update_probe_resp(wlc, bsscfg, suspend);
 }
 
-/* prepares pdu for transmission. returns BCM error codes */
-int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu, uint *fifop)
-{
-       uint fifo;
-       struct d11txh *txh;
-       struct ieee80211_hdr *h;
-       struct scb *scb;
-
-       txh = (struct d11txh *) (pdu->data);
-       h = (struct ieee80211_hdr *)((u8 *) (txh + 1) + D11_PHY_HDR_LEN);
-
-       /* get the pkt queue info. This was put at brcms_c_sendctl or
-        * brcms_c_send for PDU */
-       fifo = le16_to_cpu(txh->TxFrameID) & TXFID_QUEUE_MASK;
-
-       scb = NULL;
-
-       *fifop = fifo;
-
-       /* return if insufficient dma resources */
-       if (*wlc->core->txavail[fifo] < MAX_DMA_SEGS) {
-               /* Mark precedences related to this FIFO, unsendable */
-               /* A fifo is full. Clear precedences related to that FIFO */
-               wlc->tx_prec_map &= ~(wlc->fifo2prec_map[fifo]);
-               return -EBUSY;
-       }
-       return 0;
-}
-
 int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
                           uint *blocks)
 {
@@ -7977,13 +7522,15 @@ int brcms_c_get_curband(struct brcms_c_info *wlc)
 void brcms_c_wait_for_tx_completion(struct brcms_c_info *wlc, bool drop)
 {
        int timeout = 20;
+       int i;
 
-       /* flush packet queue when requested */
-       if (drop)
-               brcmu_pktq_flush(&wlc->pkt_queue->q, false, NULL, NULL);
+       /* Kick DMA to send any pending AMPDU */
+       for (i = 0; i < ARRAY_SIZE(wlc->hw->di); i++)
+               if (wlc->hw->di[i])
+                       dma_txflush(wlc->hw->di[i]);
 
        /* wait for queue and DMA fifos to run dry */
-       while (!pktq_empty(&wlc->pkt_queue->q) || brcms_txpktpendtot(wlc) > 0) {
+       while (brcms_txpktpendtot(wlc) > 0) {
                brcms_msleep(wlc->wl, 1);
 
                if (--timeout == 0)
@@ -8032,8 +7579,6 @@ static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
        uint len;
        bool is_amsdu;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
-
        /* frame starts with rxhdr */
        rxh = (struct d11rxhdr *) (p->data);
 
@@ -8043,8 +7588,9 @@ static void brcms_c_recv(struct brcms_c_info *wlc, struct sk_buff *p)
        /* MAC inserts 2 pad bytes for a4 headers or QoS or A-MSDU subframes */
        if (rxh->RxStatus1 & RXS_PBPRES) {
                if (p->len < 2) {
-                       wiphy_err(wlc->wiphy, "wl%d: recv: rcvd runt of "
-                                 "len %d\n", wlc->pub->unit, p->len);
+                       brcms_err(wlc->hw->d11core,
+                                 "wl%d: recv: rcvd runt of len %d\n",
+                                 wlc->pub->unit, p->len);
                        goto toss;
                }
                skb_pull(p, 2);
@@ -8089,7 +7635,6 @@ brcms_b_recv(struct brcms_hardware *wlc_hw, uint fifo, bool bound)
        uint n = 0;
        uint bound_limit = bound ? RXBND : -1;
 
-       BCMMSG(wlc_hw->wlc->wiphy, "wl%d\n", wlc_hw->unit);
        skb_queue_head_init(&recv_frames);
 
        /* gather received frames */
@@ -8140,10 +7685,9 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
        u32 macintstatus;
        struct brcms_hardware *wlc_hw = wlc->hw;
        struct bcma_device *core = wlc_hw->d11core;
-       struct wiphy *wiphy = wlc->wiphy;
 
        if (brcms_deviceremoved(wlc)) {
-               wiphy_err(wiphy, "wl%d: %s: dead chip\n", wlc_hw->unit,
+               brcms_err(core, "wl%d: %s: dead chip\n", wlc_hw->unit,
                          __func__);
                brcms_down(wlc->wl);
                return false;
@@ -8153,8 +7697,8 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
        macintstatus = wlc->macintstatus;
        wlc->macintstatus = 0;
 
-       BCMMSG(wlc->wiphy, "wl%d: macintstatus 0x%x\n",
-              wlc_hw->unit, macintstatus);
+       brcms_dbg_int(core, "wl%d: macintstatus 0x%x\n",
+                     wlc_hw->unit, macintstatus);
 
        WARN_ON(macintstatus & MI_PRQ); /* PRQ Interrupt in non-MBSS */
 
@@ -8164,7 +7708,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
                if (brcms_b_txstatus(wlc->hw, bounded, &fatal))
                        wlc->macintstatus |= MI_TFS;
                if (fatal) {
-                       wiphy_err(wiphy, "MI_TFS: fatal\n");
+                       brcms_err(core, "MI_TFS: fatal\n");
                        goto fatal;
                }
        }
@@ -8174,7 +7718,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
 
        /* ATIM window end */
        if (macintstatus & MI_ATIMWINEND) {
-               BCMMSG(wlc->wiphy, "end of ATIM window\n");
+               brcms_dbg_info(core, "end of ATIM window\n");
                bcma_set32(core, D11REGOFFS(maccommand), wlc->qvalid);
                wlc->qvalid = 0;
        }
@@ -8192,7 +7736,7 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
                wlc_phy_noise_sample_intr(wlc_hw->band->pi);
 
        if (macintstatus & MI_GP0) {
-               wiphy_err(wiphy, "wl%d: PSM microcode watchdog fired at %d "
+               brcms_err(core, "wl%d: PSM microcode watchdog fired at %d "
                          "(seconds). Resetting.\n", wlc_hw->unit, wlc_hw->now);
 
                printk_once("%s : PSM Watchdog, chipid 0x%x, chiprev 0x%x\n",
@@ -8206,15 +7750,11 @@ bool brcms_c_dpc(struct brcms_c_info *wlc, bool bounded)
                bcma_write32(core, D11REGOFFS(gptimer), 0);
 
        if (macintstatus & MI_RFDISABLE) {
-               BCMMSG(wlc->wiphy, "wl%d: BMAC Detected a change on the"
-                      " RF Disable Input\n", wlc_hw->unit);
+               brcms_dbg_info(core, "wl%d: BMAC Detected a change on the"
+                              " RF Disable Input\n", wlc_hw->unit);
                brcms_rfkill_set_hw_state(wlc->wl);
        }
 
-       /* send any enq'd tx packets. Just makes sure to jump start tx */
-       if (!pktq_empty(&wlc->pkt_queue->q))
-               brcms_c_send_q(wlc);
-
        /* it isn't done and needs to be resched if macintstatus is non-zero */
        return wlc->macintstatus != 0;
 
@@ -8229,7 +7769,7 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
        struct ieee80211_channel *ch = wlc->pub->ieee_hw->conf.channel;
        u16 chanspec;
 
-       BCMMSG(wlc->wiphy, "wl%d\n", wlc->pub->unit);
+       brcms_dbg_info(core, "wl%d\n", wlc->pub->unit);
 
        chanspec = ch20mhz_chspec(ch->hw_value);
 
@@ -8286,9 +7826,6 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
        bcma_set16(core, D11REGOFFS(ifs_ctl), IFS_USEEDCF);
        brcms_c_edcf_setparams(wlc, false);
 
-       /* Init precedence maps for empty FIFOs */
-       brcms_c_tx_prec_map_init(wlc);
-
        /* read the ucode version if we have not yet done so */
        if (wlc->ucode_rev == 0) {
                wlc->ucode_rev =
@@ -8303,9 +7840,6 @@ void brcms_c_init(struct brcms_c_info *wlc, bool mute_tx)
        if (mute_tx)
                brcms_b_mute(wlc->hw, true);
 
-       /* clear tx flow control */
-       brcms_c_txflowcontrol_reset(wlc);
-
        /* enable the RF Disable Delay timer */
        bcma_write32(core, D11REGOFFS(rfdisabledly), RFDISABLE_DEFAULT);
 
@@ -8464,15 +7998,6 @@ brcms_c_attach(struct brcms_info *wl, struct bcma_device *core, uint unit,
         * Complete the wlc default state initializations..
         */
 
-       /* allocate our initial queue */
-       wlc->pkt_queue = brcms_c_txq_alloc(wlc);
-       if (wlc->pkt_queue == NULL) {
-               wiphy_err(wl->wiphy, "wl%d: %s: failed to malloc tx queue\n",
-                         unit, __func__);
-               err = 100;
-               goto fail;
-       }
-
        wlc->bsscfg->wlc = wlc;
 
        wlc->mimoft = FT_HT;
index 8debc74c54e1a63b5d9be1eae54e3c52d33375ba..fb447747c2c6e9975b681a7d42f0dc6ae5ad00bd 100644 (file)
 
 #define DATA_BLOCK_TX_SUPR     (1 << 4)
 
-/* 802.1D Priority to TX FIFO number for wme */
-extern const u8 prio2fifo[];
-
 /* Ucode MCTL_WAKE override bits */
 #define BRCMS_WAKE_OVERRIDE_CLKCTL     0x01
 #define BRCMS_WAKE_OVERRIDE_PHYREG     0x02
@@ -242,7 +239,6 @@ struct brcms_core {
 
        /* fifo */
        uint *txavail[NFIFO];   /* # tx descriptors available */
-       s16 txpktpend[NFIFO];   /* tx admission control */
 
        struct macstat *macstat_snapshot;       /* mac hw prev read values */
 };
@@ -382,19 +378,6 @@ struct brcms_hardware {
                                 */
 };
 
-/* TX Queue information
- *
- * Each flow of traffic out of the device has a TX Queue with independent
- * flow control. Several interfaces may be associated with a single TX Queue
- * if they belong to the same flow of traffic from the device. For multi-channel
- * operation there are independent TX Queues for each channel.
- */
-struct brcms_txq_info {
-       struct brcms_txq_info *next;
-       struct pktq q;
-       uint stopped;           /* tx flow control bits */
-};
-
 /*
  * Principal common driver data structure.
  *
@@ -435,11 +418,8 @@ struct brcms_txq_info {
  * WDlast: last time wlc_watchdog() was called.
  * edcf_txop[IEEE80211_NUM_ACS]: current txop for each ac.
  * wme_retries: per-AC retry limits.
- * tx_prec_map: Precedence map based on HW FIFO space.
- * fifo2prec_map[NFIFO]: pointer to fifo2_prec map based on WME.
  * bsscfg: set of BSS configurations, idx 0 is default and always valid.
  * cfg: the primary bsscfg (can be AP or STA).
- * tx_queues: common TX Queue list.
  * modulecb:
  * mimoft: SIGN or 11N.
  * cck_40txbw: 11N, cck tx b/w override when in 40MHZ mode.
@@ -469,7 +449,6 @@ struct brcms_txq_info {
  * tempsense_lasttime;
  * tx_duty_cycle_ofdm: maximum allowed duty cycle for OFDM.
  * tx_duty_cycle_cck: maximum allowed duty cycle for CCK.
- * pkt_queue: txq for transmit packets.
  * wiphy:
  * pri_scb: primary Station Control Block
  */
@@ -533,14 +512,9 @@ struct brcms_c_info {
        u16 edcf_txop[IEEE80211_NUM_ACS];
 
        u16 wme_retries[IEEE80211_NUM_ACS];
-       u16 tx_prec_map;
-       u16 fifo2prec_map[NFIFO];
 
        struct brcms_bss_cfg *bsscfg;
 
-       /* tx queue */
-       struct brcms_txq_info *tx_queues;
-
        struct modulecb *modulecb;
 
        u8 mimoft;
@@ -585,7 +559,6 @@ struct brcms_c_info {
        u16 tx_duty_cycle_ofdm;
        u16 tx_duty_cycle_cck;
 
-       struct brcms_txq_info *pkt_queue;
        struct wiphy *wiphy;
        struct scb pri_scb;
 };
@@ -637,30 +610,13 @@ struct brcms_bss_cfg {
        struct brcms_bss_info *current_bss;
 };
 
-extern void brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo,
-                          struct sk_buff *p,
-                          bool commit, s8 txpktpend);
-extern void brcms_c_txfifo_complete(struct brcms_c_info *wlc, uint fifo,
-                                   s8 txpktpend);
-extern void brcms_c_txq_enq(struct brcms_c_info *wlc, struct scb *scb,
-                           struct sk_buff *sdu, uint prec);
-extern void brcms_c_print_txstatus(struct tx_status *txs);
+extern int brcms_c_txfifo(struct brcms_c_info *wlc, uint fifo,
+                          struct sk_buff *p);
 extern int brcms_b_xmtfifo_sz_get(struct brcms_hardware *wlc_hw, uint fifo,
                   uint *blocks);
 
-#if defined(DEBUG)
-extern void brcms_c_print_txdesc(struct d11txh *txh);
-#else
-static inline void brcms_c_print_txdesc(struct d11txh *txh)
-{
-}
-#endif
-
 extern int brcms_c_set_gmode(struct brcms_c_info *wlc, u8 gmode, bool config);
 extern void brcms_c_mac_promisc(struct brcms_c_info *wlc, uint filter_flags);
-extern void brcms_c_send_q(struct brcms_c_info *wlc);
-extern int brcms_c_prep_pdu(struct brcms_c_info *wlc, struct sk_buff *pdu,
-                           uint *fifo);
 extern u16 brcms_c_calc_lsig_len(struct brcms_c_info *wlc, u32 ratespec,
                                uint mac_len);
 extern u32 brcms_c_rspec_to_rts_rspec(struct brcms_c_info *wlc,
index 5855f4fd16dcd8d0dc473cd73275baae72414728..0148dec104f0369c5bc2942f3594f0d83a5e81af 100644 (file)
@@ -200,43 +200,6 @@ enum wlc_par_id {
 /* WL11N Support */
 #define AMPDU_AGG_HOST 1
 
-/* pri is priority encoded in the packet. This maps the Packet priority to
- * enqueue precedence as defined in wlc_prec_map
- */
-extern const u8 wlc_prio2prec_map[];
-#define BRCMS_PRIO_TO_PREC(pri)        wlc_prio2prec_map[(pri) & 7]
-
-#define        BRCMS_PREC_COUNT        16      /* Max precedence level implemented */
-
-/* Mask to describe all precedence levels */
-#define BRCMS_PREC_BMP_ALL             MAXBITVAL(BRCMS_PREC_COUNT)
-
-/*
- * This maps priority to one precedence higher - Used by PS-Poll response
- * packets to simulate enqueue-at-head operation, but still maintain the
- * order on the queue
- */
-#define BRCMS_PRIO_TO_HI_PREC(pri)     min(BRCMS_PRIO_TO_PREC(pri) + 1,\
-                                           BRCMS_PREC_COUNT - 1)
-
-/* Define a bitmap of precedences comprised by each AC */
-#define BRCMS_PREC_BMP_AC_BE   (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BE)) | \
-                       NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BE)) | \
-                       NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_EE)) |    \
-                       NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_EE)))
-#define BRCMS_PREC_BMP_AC_BK   (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_BK)) | \
-                       NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_BK)) | \
-                       NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NONE)) |  \
-                       NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NONE)))
-#define BRCMS_PREC_BMP_AC_VI   (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_CL)) | \
-                       NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_CL)) | \
-                       NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VI)) |    \
-                       NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VI)))
-#define BRCMS_PREC_BMP_AC_VO   (NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_VO)) | \
-                       NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_VO)) | \
-                       NBITVAL(BRCMS_PRIO_TO_PREC(PRIO_8021D_NC)) |    \
-                       NBITVAL(BRCMS_PRIO_TO_HI_PREC(PRIO_8021D_NC)))
-
 /* network protection config */
 #define        BRCMS_PROT_G_SPEC               1       /* SPEC g protection */
 #define        BRCMS_PROT_G_OVR                2       /* SPEC g prot override */
index ed1d1aa71d2d6a3541f285e7155a46d53bfe425b..dd9162722495333df13296c80d89c20ea9058d74 100644 (file)
@@ -23,6 +23,7 @@
 #include "channel.h"
 #include "main.h"
 #include "stf.h"
+#include "debug.h"
 
 #define MIN_SPATIAL_EXPANSION  0
 #define MAX_SPATIAL_EXPANSION  1
@@ -160,8 +161,8 @@ bool brcms_c_stf_stbc_rx_set(struct brcms_c_info *wlc, s32 int_val)
 static int brcms_c_stf_txcore_set(struct brcms_c_info *wlc, u8 Nsts,
                                  u8 core_mask)
 {
-       BCMMSG(wlc->wiphy, "wl%d: Nsts %d core_mask %x\n",
-                wlc->pub->unit, Nsts, core_mask);
+       brcms_dbg_ht(wlc->hw->d11core, "wl%d: Nsts %d core_mask %x\n",
+                    wlc->pub->unit, Nsts, core_mask);
 
        if (hweight8(core_mask) > wlc->stf->txstreams)
                core_mask = 0;
@@ -194,7 +195,8 @@ static int brcms_c_stf_spatial_policy_set(struct brcms_c_info *wlc, int val)
        int i;
        u8 core_mask = 0;
 
-       BCMMSG(wlc->wiphy, "wl%d: val %x\n", wlc->pub->unit, val);
+       brcms_dbg_ht(wlc->hw->d11core, "wl%d: val %x\n", wlc->pub->unit,
+                    val);
 
        wlc->stf->spatial_policy = (s8) val;
        for (i = 1; i <= MAX_STREAMS_SUPPORTED; i++) {
index e11ae83111e499411670af3ac4fc72158ba77d25..ae1f3ad40d459f7722f57a0c40744e1ea58f6f18 100644 (file)
 
 #define BCMMSG(dev, fmt, args...)              \
 do {                                           \
-       if (brcm_msg_level & LOG_TRACE_VAL)     \
+       if (brcm_msg_level & BRCM_DL_INFO)      \
                wiphy_err(dev, "%s: " fmt, __func__, ##args);   \
 } while (0)
 
@@ -281,7 +281,6 @@ struct ieee80211_tx_queue_params;
 struct brcms_info;
 struct brcms_c_info;
 struct brcms_hardware;
-struct brcms_txq_info;
 struct brcms_band;
 struct dma_pub;
 struct si_pub;
index f0d8c04a9c8cd13b03962b8855acdc69f8913b35..fb7cbcf81179bbc31f70e9557def1db9593dffb8 100644 (file)
 #define PM_OFF 0
 #define PM_MAX 1
 
-/* Message levels */
-#define LOG_ERROR_VAL          0x00000001
-#define LOG_TRACE_VAL          0x00000002
+/* Debug levels */
+#define BRCM_DL_INFO           0x00000001
+#define BRCM_DL_MAC80211       0x00000002
+#define BRCM_DL_RX             0x00000004
+#define BRCM_DL_TX             0x00000008
+#define BRCM_DL_INT            0x00000010
+#define BRCM_DL_DMA            0x00000020
+#define BRCM_DL_HT             0x00000040
 
 #define PM_OFF 0
 #define PM_MAX 1
index 29b8fa1adefde125d62608f3b9513e53afba247a..46938bc9886dcee5bf1c43951d9dc29647da2d26 100644 (file)
@@ -1788,10 +1788,7 @@ static int ipw2100_up(struct ipw2100_priv *priv, int deferred)
        }
 
        /* Initialize the geo */
-       if (libipw_set_geo(priv->ieee, &ipw_geos[0])) {
-               printk(KERN_WARNING DRV_NAME "Could not set geo\n");
-               return 0;
-       }
+       libipw_set_geo(priv->ieee, &ipw_geos[0]);
        priv->ieee->freq_band = LIBIPW_24GHZ_BAND;
 
        lock = LOCK_NONE;
index 768bf612533e04317feb756efa17563400ce6ab2..482f505f3f3575e57ba8852db8c7c4abd7316cbf 100644 (file)
@@ -11269,10 +11269,31 @@ static const struct libipw_geo ipw_geos[] = {
         }
 };
 
+static void ipw_set_geo(struct ipw_priv *priv)
+{
+       int j;
+
+       for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) {
+               if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE],
+                           ipw_geos[j].name, 3))
+                       break;
+       }
+
+       if (j == ARRAY_SIZE(ipw_geos)) {
+               IPW_WARNING("SKU [%c%c%c] not recognized.\n",
+                           priv->eeprom[EEPROM_COUNTRY_CODE + 0],
+                           priv->eeprom[EEPROM_COUNTRY_CODE + 1],
+                           priv->eeprom[EEPROM_COUNTRY_CODE + 2]);
+               j = 0;
+       }
+
+       libipw_set_geo(priv->ieee, &ipw_geos[j]);
+}
+
 #define MAX_HW_RESTARTS 5
 static int ipw_up(struct ipw_priv *priv)
 {
-       int rc, i, j;
+       int rc, i;
 
        /* Age scan list entries found before suspend */
        if (priv->suspend_time) {
@@ -11310,22 +11331,7 @@ static int ipw_up(struct ipw_priv *priv)
                memcpy(priv->net_dev->dev_addr, priv->mac_addr, ETH_ALEN);
                memcpy(priv->net_dev->perm_addr, priv->mac_addr, ETH_ALEN);
 
-               for (j = 0; j < ARRAY_SIZE(ipw_geos); j++) {
-                       if (!memcmp(&priv->eeprom[EEPROM_COUNTRY_CODE],
-                                   ipw_geos[j].name, 3))
-                               break;
-               }
-               if (j == ARRAY_SIZE(ipw_geos)) {
-                       IPW_WARNING("SKU [%c%c%c] not recognized.\n",
-                                   priv->eeprom[EEPROM_COUNTRY_CODE + 0],
-                                   priv->eeprom[EEPROM_COUNTRY_CODE + 1],
-                                   priv->eeprom[EEPROM_COUNTRY_CODE + 2]);
-                       j = 0;
-               }
-               if (libipw_set_geo(priv->ieee, &ipw_geos[j])) {
-                       IPW_WARNING("Could not set geography.");
-                       return 0;
-               }
+               ipw_set_geo(priv);
 
                if (priv->status & STATUS_RF_KILL_SW) {
                        IPW_WARNING("Radio disabled by module parameter.\n");
index 0b22fb4217359f72414e2e14726d34d683f422e2..6eede52ad8c0fbc0581a2b3a68d302cb589f4dde 100644 (file)
@@ -978,7 +978,7 @@ extern void libipw_network_reset(struct libipw_network *network);
 /* libipw_geo.c */
 extern const struct libipw_geo *libipw_get_geo(struct libipw_device
                                                     *ieee);
-extern int libipw_set_geo(struct libipw_device *ieee,
+extern void libipw_set_geo(struct libipw_device *ieee,
                             const struct libipw_geo *geo);
 
 extern int libipw_is_valid_channel(struct libipw_device *ieee,
index c9fe3c99cb003c087729b12380b16df014827f8b..218f2a32de21758e105bb4a12e782e65e11ea90a 100644 (file)
@@ -132,7 +132,7 @@ u8 libipw_freq_to_channel(struct libipw_device * ieee, u32 freq)
        return 0;
 }
 
-int libipw_set_geo(struct libipw_device *ieee,
+void libipw_set_geo(struct libipw_device *ieee,
                      const struct libipw_geo *geo)
 {
        memcpy(ieee->geo.name, geo->name, 3);
@@ -143,7 +143,6 @@ int libipw_set_geo(struct libipw_device *ieee,
               sizeof(struct libipw_channel));
        memcpy(ieee->geo.a, geo->a, ieee->geo.a_channels *
               sizeof(struct libipw_channel));
-       return 0;
 }
 
 const struct libipw_geo *libipw_get_geo(struct libipw_device *ieee)
index 87e5398943308665618cc85a78aa933fa5d7df48..e0b9d7fa5de0d43d74e130b6c91d4ad0078ecf19 100644 (file)
@@ -516,7 +516,7 @@ static void
 il3945_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
 {
        struct ieee80211_hdr *header;
-       struct ieee80211_rx_status rx_status;
+       struct ieee80211_rx_status rx_status = {};
        struct il_rx_pkt *pkt = rxb_addr(rxb);
        struct il3945_rx_frame_stats *rx_stats = IL_RX_STATS(pkt);
        struct il3945_rx_frame_hdr *rx_hdr = IL_RX_HDR(pkt);
index eac4dc8bc879ffabeacf558b576f6a6fe8b5d9ed..07ffa575e3efb7ccdf37baaddb43751f67b6bb88 100644 (file)
@@ -613,7 +613,7 @@ void
 il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
 {
        struct ieee80211_hdr *header;
-       struct ieee80211_rx_status rx_status;
+       struct ieee80211_rx_status rx_status = {};
        struct il_rx_pkt *pkt = rxb_addr(rxb);
        struct il_rx_phy_res *phy_res;
        __le32 rx_pkt_status;
@@ -686,7 +686,7 @@ il4965_hdl_rx(struct il_priv *il, struct il_rx_buf *rxb)
 
        /* TSF isn't reliable. In order to allow smooth user experience,
         * this W/A doesn't propagate it to the mac80211 */
-       /*rx_status.flag |= RX_FLAG_MACTIME_MPDU; */
+       /*rx_status.flag |= RX_FLAG_MACTIME_START; */
 
        il->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
 
index b4bb813362bdbeb44afab3dd7b73d74dd556feb3..e254cba4557adbf12d6f3e7e0534b3c36c73c2d4 100644 (file)
@@ -2919,9 +2919,8 @@ do {                                                                      \
 #define IL_DBG(level, fmt, args...)                                    \
 do {                                                                   \
        if (il_get_debug_level(il) & level)                             \
-               dev_printk(KERN_ERR, &il->hw->wiphy->dev,               \
-                        "%c %s " fmt, in_interrupt() ? 'I' : 'U',      \
-                       __func__ , ## args);                            \
+               dev_err(&il->hw->wiphy->dev, "%c %s " fmt,              \
+                       in_interrupt() ? 'I' : 'U', __func__ , ##args); \
 } while (0)
 
 #define il_print_hex_dump(il, level, p, len)                           \
index 727fbb5db9da0b41b10b6132267d4b91f533f852..5cf43236421ee57a4b3145ded322e49fe05ca6f3 100644 (file)
@@ -133,12 +133,3 @@ config IWLWIFI_P2P
          support when it is loaded.
 
          Say Y only if you want to experiment with P2P.
-
-config IWLWIFI_EXPERIMENTAL_MFP
-       bool "support MFP (802.11w) even if uCode doesn't advertise"
-       depends on IWLWIFI
-       help
-         This option enables experimental MFP (802.11W) support
-         even if the microcode doesn't advertise it.
-
-         Say Y only if you want to experiment with MFP.
index 75e12f29d9eb7dc0e4a16bb92aa5cd6aa587b062..33b3ad2e546bc9c4fbad24516c2ab1d279888041 100644 (file)
@@ -176,8 +176,8 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr);
 /* lib */
 int iwlagn_send_tx_power(struct iwl_priv *priv);
 void iwlagn_temperature(struct iwl_priv *priv);
-int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
-void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control);
+int iwlagn_txfifo_flush(struct iwl_priv *priv);
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv);
 int iwlagn_send_beacon_cmd(struct iwl_priv *priv);
 int iwl_send_statistics_request(struct iwl_priv *priv,
                                u8 flags, bool clear);
index 01128c96b5d8c309e800bd08b01f378ceb382613..71ab76b2b39d18da16518e99b5d36ab90ac87042 100644 (file)
@@ -986,8 +986,7 @@ struct iwl_rem_sta_cmd {
 
 #define IWL_AGG_TX_QUEUE_MSK           cpu_to_le32(0xffc00)
 
-#define IWL_DROP_SINGLE                0
-#define IWL_DROP_ALL           (BIT(IWL_RXON_CTX_BSS) | BIT(IWL_RXON_CTX_PAN))
+#define IWL_DROP_ALL                   BIT(1)
 
 /*
  * REPLY_TXFIFO_FLUSH = 0x1e(command and response)
@@ -1004,14 +1003,14 @@ struct iwl_rem_sta_cmd {
  * the flush operation ends when both the scheduler DMA done and TXFIFO empty
  * are set.
  *
- * @fifo_control: bit mask for which queues to flush
+ * @queue_control: bit mask for which queues to flush
  * @flush_control: flush controls
  *     0: Dump single MSDU
  *     1: Dump multiple MSDU according to PS, INVALID STA, TTL, TID disable.
  *     2: Dump all FIFO
  */
 struct iwl_txfifo_flush_cmd {
-       __le32 fifo_control;
+       __le32 queue_control;
        __le16 flush_control;
        __le16 reserved;
 } __packed;
index 1a98fa3ab06df6fbf9ae8ec3197680adef182883..769a08bca86f1551be49af3ef4317529fab0402c 100644 (file)
@@ -2101,7 +2101,7 @@ static ssize_t iwl_dbgfs_txfifo_flush_write(struct file *file,
        if (iwl_is_rfkill(priv))
                return -EFAULT;
 
-       iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
+       iwlagn_dev_txfifo_flush(priv);
 
        return count;
 }
index 8141f91c3725bd3c8f26d9830e61574dd3b4586f..29c571a56251d20dd6f5992d1b2d5805bb3725fc 100644 (file)
@@ -789,7 +789,6 @@ struct iwl_priv {
        /* remain-on-channel offload support */
        struct ieee80211_channel *hw_roc_channel;
        struct delayed_work hw_roc_disable_work;
-       enum nl80211_channel_type hw_roc_chantype;
        int hw_roc_duration;
        bool hw_roc_setup, hw_roc_start_notified;
 
index bef88c1a2c9b1a83bfbcfdc584708edfb64e6593..7e59be4b89b8e7106bdfd3bdb7a563dfca0be04b 100644 (file)
@@ -136,7 +136,7 @@ int iwlagn_manage_ibss_station(struct iwl_priv *priv,
  *  1. acquire mutex before calling
  *  2. make sure rf is on and not in exit state
  */
-int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
+int iwlagn_txfifo_flush(struct iwl_priv *priv)
 {
        struct iwl_txfifo_flush_cmd flush_cmd;
        struct iwl_host_cmd cmd = {
@@ -146,35 +146,34 @@ int iwlagn_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
                .data = { &flush_cmd, },
        };
 
-       might_sleep();
-
        memset(&flush_cmd, 0, sizeof(flush_cmd));
-       if (flush_control & BIT(IWL_RXON_CTX_BSS))
-               flush_cmd.fifo_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK |
-                                IWL_SCD_BE_MSK | IWL_SCD_BK_MSK |
-                                IWL_SCD_MGMT_MSK;
-       if ((flush_control & BIT(IWL_RXON_CTX_PAN)) &&
-           (priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
-               flush_cmd.fifo_control |= IWL_PAN_SCD_VO_MSK |
-                               IWL_PAN_SCD_VI_MSK | IWL_PAN_SCD_BE_MSK |
-                               IWL_PAN_SCD_BK_MSK | IWL_PAN_SCD_MGMT_MSK |
-                               IWL_PAN_SCD_MULTICAST_MSK;
+
+       flush_cmd.queue_control = IWL_SCD_VO_MSK | IWL_SCD_VI_MSK |
+                                 IWL_SCD_BE_MSK | IWL_SCD_BK_MSK |
+                                 IWL_SCD_MGMT_MSK;
+       if ((priv->valid_contexts != BIT(IWL_RXON_CTX_BSS)))
+               flush_cmd.queue_control |= IWL_PAN_SCD_VO_MSK |
+                                          IWL_PAN_SCD_VI_MSK |
+                                          IWL_PAN_SCD_BE_MSK |
+                                          IWL_PAN_SCD_BK_MSK |
+                                          IWL_PAN_SCD_MGMT_MSK |
+                                          IWL_PAN_SCD_MULTICAST_MSK;
 
        if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE)
-               flush_cmd.fifo_control |= IWL_AGG_TX_QUEUE_MSK;
+               flush_cmd.queue_control |= IWL_AGG_TX_QUEUE_MSK;
 
-       IWL_DEBUG_INFO(priv, "fifo queue control: 0X%x\n",
-                      flush_cmd.fifo_control);
-       flush_cmd.flush_control = cpu_to_le16(flush_control);
+       IWL_DEBUG_INFO(priv, "queue control: 0x%x\n",
+                      flush_cmd.queue_control);
+       flush_cmd.flush_control = cpu_to_le16(IWL_DROP_ALL);
 
        return iwl_dvm_send_cmd(priv, &cmd);
 }
 
-void iwlagn_dev_txfifo_flush(struct iwl_priv *priv, u16 flush_control)
+void iwlagn_dev_txfifo_flush(struct iwl_priv *priv)
 {
        mutex_lock(&priv->mutex);
        ieee80211_stop_queues(priv->hw);
-       if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
+       if (iwlagn_txfifo_flush(priv)) {
                IWL_ERR(priv, "flush request fail\n");
                goto done;
        }
index 2d9eee93c743aa0f7bfe6d98330ccacead4fe201..fb959b00b20801476b555003e08327d7f7cfafb5 100644 (file)
@@ -168,10 +168,13 @@ int iwlagn_mac_setup_register(struct iwl_priv *priv,
                hw->flags |= IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                             IEEE80211_HW_SUPPORTS_STATIC_SMPS;
 
-#ifndef CONFIG_IWLWIFI_EXPERIMENTAL_MFP
-       /* enable 11w if the uCode advertise */
-       if (capa->flags & IWL_UCODE_TLV_FLAGS_MFP)
-#endif /* !CONFIG_IWLWIFI_EXPERIMENTAL_MFP */
+       /*
+        * Enable 11w if advertised by firmware and software crypto
+        * is not enabled (as the firmware will interpret some mgmt
+        * packets, so enabling it with software crypto isn't safe)
+        */
+       if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_MFP &&
+           !iwlwifi_mod_params.sw_crypto)
                hw->flags |= IEEE80211_HW_MFP_CAPABLE;
 
        hw->sta_data_size = sizeof(struct iwl_station_priv);
@@ -1019,7 +1022,7 @@ static void iwlagn_mac_flush(struct ieee80211_hw *hw, bool drop)
         */
        if (drop) {
                IWL_DEBUG_MAC80211(priv, "send flush command\n");
-               if (iwlagn_txfifo_flush(priv, IWL_DROP_ALL)) {
+               if (iwlagn_txfifo_flush(priv)) {
                        IWL_ERR(priv, "flush request fail\n");
                        goto done;
                }
@@ -1032,8 +1035,8 @@ done:
 }
 
 static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
+                                    struct ieee80211_vif *vif,
                                     struct ieee80211_channel *channel,
-                                    enum nl80211_channel_type channel_type,
                                     int duration)
 {
        struct iwl_priv *priv = IWL_MAC80211_GET_DVM(hw);
@@ -1065,7 +1068,6 @@ static int iwlagn_mac_remain_on_channel(struct ieee80211_hw *hw,
        }
 
        priv->hw_roc_channel = channel;
-       priv->hw_roc_chantype = channel_type;
        /* convert from ms to TU */
        priv->hw_roc_duration = DIV_ROUND_UP(1000 * duration, 1024);
        priv->hw_roc_start_notified = false;
index 30e761d31e9827d6c4720d273b1fa6b8a2ab8fc8..e3a07c916812c2a5d4cfda28018dded8b67c11e2 100644 (file)
@@ -511,7 +511,7 @@ static void iwl_bg_tx_flush(struct work_struct *work)
                return;
 
        IWL_DEBUG_INFO(priv, "device request: flush all tx frames\n");
-       iwlagn_dev_txfifo_flush(priv, IWL_DROP_ALL);
+       iwlagn_dev_txfifo_flush(priv);
 }
 
 /*
@@ -1191,8 +1191,6 @@ static void iwl_option_config(struct iwl_priv *priv)
 
 static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
 {
-       priv->eeprom_data->sku = priv->eeprom_data->sku;
-
        if (priv->eeprom_data->sku & EEPROM_SKU_CAP_11N_ENABLE &&
            !priv->cfg->ht_params) {
                IWL_ERR(priv, "Invalid 11n configuration\n");
@@ -1204,7 +1202,7 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
                return -EINVAL;
        }
 
-       IWL_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku);
+       IWL_DEBUG_INFO(priv, "Device SKU: 0x%X\n", priv->eeprom_data->sku);
 
        priv->hw_params.tx_chains_num =
                num_of_ant(priv->eeprom_data->valid_tx_ant);
@@ -1214,9 +1212,9 @@ static int iwl_eeprom_init_hw_params(struct iwl_priv *priv)
                priv->hw_params.rx_chains_num =
                        num_of_ant(priv->eeprom_data->valid_rx_ant);
 
-       IWL_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n",
-                priv->eeprom_data->valid_tx_ant,
-                priv->eeprom_data->valid_rx_ant);
+       IWL_DEBUG_INFO(priv, "Valid Tx ant: 0x%X, Valid Rx ant: 0x%X\n",
+                      priv->eeprom_data->valid_tx_ant,
+                      priv->eeprom_data->valid_rx_ant);
 
        return 0;
 }
@@ -1231,7 +1229,7 @@ static struct iwl_op_mode *iwl_op_mode_dvm_start(struct iwl_trans *trans,
        struct iwl_op_mode *op_mode;
        u16 num_mac;
        u32 ucode_flags;
-       struct iwl_trans_config trans_cfg;
+       struct iwl_trans_config trans_cfg = {};
        static const u8 no_reclaim_cmds[] = {
                REPLY_RX_PHY_CMD,
                REPLY_RX_MPDU_CMD,
@@ -1507,10 +1505,6 @@ static void iwl_op_mode_dvm_stop(struct iwl_op_mode *op_mode)
 
        iwl_tt_exit(priv);
 
-       /*This will stop the queues, move the device to low power state */
-       priv->ucode_loaded = false;
-       iwl_trans_stop_device(priv->trans);
-
        kfree(priv->eeprom_blob);
        iwl_free_eeprom_data(priv->eeprom_data);
 
@@ -1926,8 +1920,6 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
         * commands by clearing the ready bit */
        clear_bit(STATUS_READY, &priv->status);
 
-       wake_up(&priv->trans->wait_command_queue);
-
        if (!ondemand) {
                /*
                 * If firmware keep reloading, then it indicate something
index 5a9c325804f6dcdc8d47d44faf15dec1051d4471..cac4f37cc427531871049d775a6fba7f315638a8 100644 (file)
@@ -631,8 +631,6 @@ static int iwlagn_rx_card_state_notif(struct iwl_priv *priv,
             test_bit(STATUS_RF_KILL_HW, &priv->status)))
                wiphy_rfkill_set_hw_state(priv->hw->wiphy,
                        test_bit(STATUS_RF_KILL_HW, &priv->status));
-       else
-               wake_up(&priv->trans->wait_command_queue);
        return 0;
 }
 
@@ -901,7 +899,7 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
                            struct iwl_device_cmd *cmd)
 {
        struct ieee80211_hdr *header;
-       struct ieee80211_rx_status rx_status;
+       struct ieee80211_rx_status rx_status = {};
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        struct iwl_rx_phy_res *phy_res;
        __le32 rx_pkt_status;
@@ -951,7 +949,7 @@ static int iwlagn_rx_reply_rx(struct iwl_priv *priv,
 
        /* TSF isn't reliable. In order to allow smooth user experience,
         * this W/A doesn't propagate it to the mac80211 */
-       /*rx_status.flag |= RX_FLAG_MACTIME_MPDU;*/
+       /*rx_status.flag |= RX_FLAG_MACTIME_START;*/
 
        priv->ucode_beacon_time = le32_to_cpu(phy_res->beacon_time_stamp);
 
index f5ca73a89870727a71d6a354abebaeb01221d6f5..4ae031f6726bbe5314f18398d676ec66298f4fce 100644 (file)
@@ -1075,14 +1075,11 @@ static void iwlagn_count_tx_err_status(struct iwl_priv *priv, u16 status)
 
 static void iwlagn_set_tx_status(struct iwl_priv *priv,
                                 struct ieee80211_tx_info *info,
-                                struct iwlagn_tx_resp *tx_resp,
-                                bool is_agg)
+                                struct iwlagn_tx_resp *tx_resp)
 {
-       u16  status = le16_to_cpu(tx_resp->status.status);
+       u16 status = le16_to_cpu(tx_resp->status.status);
 
        info->status.rates[0].count = tx_resp->failure_frame + 1;
-       if (is_agg)
-               info->flags &= ~IEEE80211_TX_CTL_AMPDU;
        info->flags |= iwl_tx_status_to_mac80211(status);
        iwlagn_hwrate_to_tx_control(priv, le32_to_cpu(tx_resp->rate_n_flags),
                                    info);
@@ -1231,7 +1228,7 @@ int iwlagn_rx_reply_tx(struct iwl_priv *priv, struct iwl_rx_cmd_buffer *rxb,
                        if (is_agg && !iwl_is_tx_success(status))
                                info->flags |= IEEE80211_TX_STAT_AMPDU_NO_BACK;
                        iwlagn_set_tx_status(priv, IEEE80211_SKB_CB(skb),
-                                    tx_resp, is_agg);
+                                    tx_resp);
                        if (!is_agg)
                                iwlagn_non_agg_tx_status(priv, ctx, hdr->addr1);
 
index 2cb1efbc5ed1f3d80127f678e4c82e42046eb7c1..95e6d33f51591fde0557faff02dad0a6097a70b4 100644 (file)
@@ -254,7 +254,7 @@ static int iwl_alive_notify(struct iwl_priv *priv)
        int ret;
        int i;
 
-       iwl_trans_fw_alive(priv->trans);
+       iwl_trans_fw_alive(priv->trans, 0);
 
        if (priv->fw->ucode_capa.flags & IWL_UCODE_TLV_FLAGS_PAN &&
            priv->eeprom_data->sku & EEPROM_SKU_CAP_IPAN_ENABLE) {
index 87f465a49df142952139c7446adffdeee801385c..196266aa5a9dbdd057f6ac8ca375fe0a98334699 100644 (file)
@@ -150,7 +150,7 @@ enum iwl_led_mode {
 struct iwl_base_params {
        int eeprom_size;
        int num_of_queues;      /* def: HW dependent */
-       /* for iwl_apm_init() */
+       /* for iwl_pcie_apm_init() */
        u32 pll_cfg_val;
 
        const u16 max_ll_items;
index 678717bf62eb514906aa315efa1fbbfb5f2b2e78..b3fde5f7b9bc00e69aa80928dafc2f35dd9a136c 100644 (file)
@@ -306,7 +306,7 @@ TRACE_EVENT(iwlwifi_dev_rx_data,
                        memcpy(__get_dynamic_array(data),
                               ((u8 *)rxbuf) + offs, len - offs);
        ),
-       TP_printk("[%s] TX frame data", __get_str(dev))
+       TP_printk("[%s] RX frame data", __get_str(dev))
 );
 
 #undef TRACE_SYSTEM
index f10170fe879922b6f56a8d2a6b287d11af92421e..4a9dc9629efe7f4a92ef5847d8583b537a9fe436 100644 (file)
@@ -889,8 +889,8 @@ int iwl_eeprom_check_version(struct iwl_eeprom_data *data,
 {
        if (data->eeprom_version >= trans->cfg->eeprom_ver ||
            data->calib_version >= trans->cfg->eeprom_calib_ver) {
-               IWL_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n",
-                        data->eeprom_version, data->calib_version);
+               IWL_DEBUG_INFO(trans, "device EEPROM VER=0x%x, CALIB=0x%x\n",
+                              data->eeprom_version, data->calib_version);
                return 0;
        }
 
index 80604664174722ca4c57703e7e86592b90949b86..ec48563d3c6ad3e05f652ce936ff5fabc8cb2b2b 100644 (file)
@@ -267,7 +267,7 @@ static inline unsigned int FH_MEM_CBBC_QUEUE(unsigned int chnl)
 
 #define FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS       (20)
 #define FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS     (4)
-#define RX_RB_TIMEOUT  (0x10)
+#define RX_RB_TIMEOUT  (0x11)
 
 #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_VAL         (0x00000000)
 #define FH_RCSR_RX_CONFIG_CHNL_EN_PAUSE_EOF_VAL     (0x40000000)
index f75ea6d73ffc4e824bb9dffdb61e63607e4cccbf..e378ea6dca9c1b23c5edbc898ea07ce4d3553506 100644 (file)
@@ -221,14 +221,21 @@ struct iwl_device_cmd {
 /**
  * struct iwl_hcmd_dataflag - flag for each one of the chunks of the command
  *
- * IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's
+ * @IWL_HCMD_DFL_NOCOPY: By default, the command is copied to the host command's
  *     ring. The transport layer doesn't map the command's buffer to DMA, but
  *     rather copies it to an previously allocated DMA buffer. This flag tells
  *     the transport layer not to copy the command, but to map the existing
- *     buffer. This can save memcpy and is worth with very big comamnds.
+ *     buffer (that is passed in) instead. This saves the memcpy and allows
+ *     commands that are bigger than the fixed buffer to be submitted.
+ *     Note that a TFD entry after a NOCOPY one cannot be a normal copied one.
+ * @IWL_HCMD_DFL_DUP: Only valid without NOCOPY, duplicate the memory for this
+ *     chunk internally and free it again after the command completes. This
+ *     can (currently) be used only once per command.
+ *     Note that a TFD entry after a DUP one cannot be a normal copied one.
  */
 enum iwl_hcmd_dataflag {
        IWL_HCMD_DFL_NOCOPY     = BIT(0),
+       IWL_HCMD_DFL_DUP        = BIT(1),
 };
 
 /**
@@ -348,14 +355,17 @@ struct iwl_trans;
  * @start_fw: allocates and inits all the resources for the transport
  *     layer. Also kick a fw image.
  *     May sleep
- * @fw_alive: called when the fw sends alive notification
+ * @fw_alive: called when the fw sends alive notification. If the fw provides
+ *     the SCD base address in SRAM, then provide it here, or 0 otherwise.
  *     May sleep
  * @stop_device:stops the whole device (embedded CPU put to reset)
  *     May sleep
  * @wowlan_suspend: put the device into the correct mode for WoWLAN during
  *     suspend. This is optional, if not implemented WoWLAN will not be
  *     supported. This callback may sleep.
- * @send_cmd:send a host command
+ * @send_cmd:send a host command. Must return -ERFKILL if RFkill is asserted.
+ *     If RFkill is asserted in the middle of a SYNC host command, it must
+ *     return -ERFKILL straight away.
  *     May sleep only if CMD_SYNC is set
  * @tx: send an skb
  *     Must be atomic
@@ -385,7 +395,7 @@ struct iwl_trans_ops {
        int (*start_hw)(struct iwl_trans *iwl_trans);
        void (*stop_hw)(struct iwl_trans *iwl_trans, bool op_mode_leaving);
        int (*start_fw)(struct iwl_trans *trans, const struct fw_img *fw);
-       void (*fw_alive)(struct iwl_trans *trans);
+       void (*fw_alive)(struct iwl_trans *trans, u32 scd_addr);
        void (*stop_device)(struct iwl_trans *trans);
 
        void (*wowlan_suspend)(struct iwl_trans *trans);
@@ -438,7 +448,6 @@ enum iwl_trans_state {
  *     Set during transport allocation.
  * @hw_id_str: a string with info about HW ID. Set during transport allocation.
  * @pm_support: set to true in start_hw if link pm is supported
- * @wait_command_queue: the wait_queue for SYNC host commands
  * @dev_cmd_pool: pool for Tx cmd allocation - for internal use only.
  *     The user should use iwl_trans_{alloc,free}_tx_cmd.
  * @dev_cmd_headroom: room needed for the transport's private use before the
@@ -465,8 +474,6 @@ struct iwl_trans {
 
        bool pm_support;
 
-       wait_queue_head_t wait_command_queue;
-
        /* The following fields are internal only */
        struct kmem_cache *dev_cmd_pool;
        size_t dev_cmd_headroom;
@@ -508,13 +515,13 @@ static inline void iwl_trans_stop_hw(struct iwl_trans *trans,
        trans->state = IWL_TRANS_NO_FW;
 }
 
-static inline void iwl_trans_fw_alive(struct iwl_trans *trans)
+static inline void iwl_trans_fw_alive(struct iwl_trans *trans, u32 scd_addr)
 {
        might_sleep();
 
        trans->state = IWL_TRANS_FW_ALIVE;
 
-       trans->ops->fw_alive(trans);
+       trans->ops->fw_alive(trans, scd_addr);
 }
 
 static inline int iwl_trans_start_fw(struct iwl_trans *trans,
index 2a4675396707474fc0a0ced64009eddb967b4bec..956fe6c370bc9338ff65fd369ad7bfac428d861c 100644 (file)
@@ -69,7 +69,6 @@
 
 #include "iwl-trans.h"
 #include "iwl-drv.h"
-#include "iwl-trans.h"
 
 #include "cfg.h"
 #include "internal.h"
index 401178f44a3b130a9de6832bf10bd3e9b6e4b529..d91d2e8c62f53e687a7eb4ae513a36035c495e78 100644 (file)
@@ -73,7 +73,7 @@ struct isr_statistics {
 };
 
 /**
- * struct iwl_rx_queue - Rx queue
+ * struct iwl_rxq - Rx queue
  * @bd: driver's pointer to buffer of receive buffer descriptors (rbd)
  * @bd_dma: bus address of buffer of receive buffer descriptors (rbd)
  * @pool:
@@ -91,7 +91,7 @@ struct isr_statistics {
  *
  * NOTE:  rx_free and rx_used are used as a FIFO for iwl_rx_mem_buffers
  */
-struct iwl_rx_queue {
+struct iwl_rxq {
        __le32 *bd;
        dma_addr_t bd_dma;
        struct iwl_rx_mem_buffer pool[RX_QUEUE_SIZE + RX_FREE_BUFFERS];
@@ -157,8 +157,8 @@ struct iwl_cmd_meta {
  * 32 since we don't need so many commands pending. Since the HW
  * still uses 256 BDs for DMA though, n_bd stays 256. As a result,
  * the software buffers (in the variables @meta, @txb in struct
- * iwl_tx_queue) only have 32 entries, while the HW buffers (@tfds
- * in the same struct) have 256.
+ * iwl_txq) only have 32 entries, while the HW buffers (@tfds in
+ * the same struct) have 256.
  * This means that we end up with the following:
  *  HW entries: | 0 | ... | N * 32 | ... | N * 32 + 31 | ... | 255 |
  *  SW entries:           | 0      | ... | 31          |
@@ -182,15 +182,17 @@ struct iwl_queue {
 #define TFD_TX_CMD_SLOTS 256
 #define TFD_CMD_SLOTS 32
 
-struct iwl_pcie_tx_queue_entry {
+struct iwl_pcie_txq_entry {
        struct iwl_device_cmd *cmd;
        struct iwl_device_cmd *copy_cmd;
        struct sk_buff *skb;
+       /* buffer to free after command completes */
+       const void *free_buf;
        struct iwl_cmd_meta meta;
 };
 
 /**
- * struct iwl_tx_queue - Tx Queue for DMA
+ * struct iwl_txq - Tx Queue for DMA
  * @q: generic Rx/Tx queue descriptor
  * @tfds: transmit frame descriptors (DMA memory)
  * @entries: transmit entries (driver state)
@@ -203,10 +205,10 @@ struct iwl_pcie_tx_queue_entry {
  * A Tx queue consists of circular buffer of BDs (a.k.a. TFDs, transmit frame
  * descriptors) and required locking structures.
  */
-struct iwl_tx_queue {
+struct iwl_txq {
        struct iwl_queue q;
        struct iwl_tfd *tfds;
-       struct iwl_pcie_tx_queue_entry *entries;
+       struct iwl_pcie_txq_entry *entries;
        spinlock_t lock;
        struct timer_list stuck_timer;
        struct iwl_trans_pcie *trans_pcie;
@@ -236,7 +238,7 @@ struct iwl_tx_queue {
  * @wd_timeout: queue watchdog timeout (jiffies)
  */
 struct iwl_trans_pcie {
-       struct iwl_rx_queue rxq;
+       struct iwl_rxq rxq;
        struct work_struct rx_replenish;
        struct iwl_trans *trans;
        struct iwl_drv *drv;
@@ -258,7 +260,7 @@ struct iwl_trans_pcie {
        struct iwl_dma_ptr scd_bc_tbls;
        struct iwl_dma_ptr kw;
 
-       struct iwl_tx_queue *txq;
+       struct iwl_txq *txq;
        unsigned long queue_used[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
        unsigned long queue_stopped[BITS_TO_LONGS(IWL_MAX_HW_QUEUES)];
 
@@ -268,6 +270,8 @@ struct iwl_trans_pcie {
 
        bool ucode_write_complete;
        wait_queue_head_t ucode_write_waitq;
+       wait_queue_head_t wait_command_queue;
+
        unsigned long status;
        u8 cmd_queue;
        u8 cmd_fifo;
@@ -283,13 +287,23 @@ struct iwl_trans_pcie {
        unsigned long wd_timeout;
 };
 
-/*****************************************************
-* DRIVER STATUS FUNCTIONS
-******************************************************/
-#define STATUS_HCMD_ACTIVE     0
-#define STATUS_DEVICE_ENABLED  1
-#define STATUS_TPOWER_PMI      2
-#define STATUS_INT_ENABLED     3
+/**
+ * enum iwl_pcie_status: status of the PCIe transport
+ * @STATUS_HCMD_ACTIVE: a SYNC command is being processed
+ * @STATUS_DEVICE_ENABLED: APM is enabled
+ * @STATUS_TPOWER_PMI: the device might be asleep (need to wake it up)
+ * @STATUS_INT_ENABLED: interrupts are enabled
+ * @STATUS_RFKILL: the HW RFkill switch is in KILL position
+ * @STATUS_FW_ERROR: the fw is in error state
+ */
+enum iwl_pcie_status {
+       STATUS_HCMD_ACTIVE,
+       STATUS_DEVICE_ENABLED,
+       STATUS_TPOWER_PMI,
+       STATUS_INT_ENABLED,
+       STATUS_RFKILL,
+       STATUS_FW_ERROR,
+};
 
 #define IWL_TRANS_GET_PCIE_TRANS(_iwl_trans) \
        ((struct iwl_trans_pcie *) ((_iwl_trans)->trans_specific))
@@ -301,6 +315,10 @@ iwl_trans_pcie_get_trans(struct iwl_trans_pcie *trans_pcie)
                            trans_specific);
 }
 
+/*
+ * Convention: trans API functions: iwl_trans_pcie_XXX
+ *     Other functions: iwl_pcie_XXX
+ */
 struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
                                       const struct pci_device_id *ent,
                                       const struct iwl_cfg *cfg);
@@ -309,50 +327,43 @@ void iwl_trans_pcie_free(struct iwl_trans *trans);
 /*****************************************************
 * RX
 ******************************************************/
-void iwl_bg_rx_replenish(struct work_struct *data);
-void iwl_irq_tasklet(struct iwl_trans *trans);
-void iwl_rx_replenish(struct iwl_trans *trans);
-void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
-                                  struct iwl_rx_queue *q);
+int iwl_pcie_rx_init(struct iwl_trans *trans);
+void iwl_pcie_tasklet(struct iwl_trans *trans);
+int iwl_pcie_rx_stop(struct iwl_trans *trans);
+void iwl_pcie_rx_free(struct iwl_trans *trans);
 
 /*****************************************************
-* ICT
+* ICT - interrupt handling
 ******************************************************/
-void iwl_reset_ict(struct iwl_trans *trans);
-void iwl_disable_ict(struct iwl_trans *trans);
-int iwl_alloc_isr_ict(struct iwl_trans *trans);
-void iwl_free_isr_ict(struct iwl_trans *trans);
-irqreturn_t iwl_isr_ict(int irq, void *data);
+irqreturn_t iwl_pcie_isr_ict(int irq, void *data);
+int iwl_pcie_alloc_ict(struct iwl_trans *trans);
+void iwl_pcie_free_ict(struct iwl_trans *trans);
+void iwl_pcie_reset_ict(struct iwl_trans *trans);
+void iwl_pcie_disable_ict(struct iwl_trans *trans);
 
 /*****************************************************
 * TX / HCMD
 ******************************************************/
-void iwl_txq_update_write_ptr(struct iwl_trans *trans,
-                             struct iwl_tx_queue *txq);
-int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
-                                struct iwl_tx_queue *txq,
-                                dma_addr_t addr, u16 len, u8 reset);
-int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id);
-int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
-void iwl_tx_cmd_complete(struct iwl_trans *trans,
-                        struct iwl_rx_cmd_buffer *rxb, int handler_status);
-void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
-                                      struct iwl_tx_queue *txq,
-                                      u16 byte_cnt);
+int iwl_pcie_tx_init(struct iwl_trans *trans);
+void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr);
+int iwl_pcie_tx_stop(struct iwl_trans *trans);
+void iwl_pcie_tx_free(struct iwl_trans *trans);
 void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
                               int sta_id, int tid, int frame_limit, u16 ssn);
 void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int queue);
-void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-                     enum dma_data_direction dma_dir);
-int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
-                        struct sk_buff_head *skbs);
-int iwl_queue_space(const struct iwl_queue *q);
-
+int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
+                     struct iwl_device_cmd *dev_cmd, int txq_id);
+void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq);
+int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd);
+void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
+                           struct iwl_rx_cmd_buffer *rxb, int handler_status);
+void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
+                           struct sk_buff_head *skbs);
 /*****************************************************
 * Error handling
 ******************************************************/
-int iwl_dump_fh(struct iwl_trans *trans, char **buf);
-void iwl_dump_csr(struct iwl_trans *trans);
+int iwl_pcie_dump_fh(struct iwl_trans *trans, char **buf);
+void iwl_pcie_dump_csr(struct iwl_trans *trans);
 
 /*****************************************************
 * Helpers
@@ -388,7 +399,7 @@ static inline void iwl_enable_rfkill_int(struct iwl_trans *trans)
 }
 
 static inline void iwl_wake_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
+                                 struct iwl_txq *txq)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
@@ -399,7 +410,7 @@ static inline void iwl_wake_queue(struct iwl_trans *trans,
 }
 
 static inline void iwl_stop_queue(struct iwl_trans *trans,
-                                 struct iwl_tx_queue *txq)
+                                 struct iwl_txq *txq)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
@@ -411,7 +422,7 @@ static inline void iwl_stop_queue(struct iwl_trans *trans,
                                    txq->q.id);
 }
 
-static inline int iwl_queue_used(const struct iwl_queue *q, int i)
+static inline bool iwl_queue_used(const struct iwl_queue *q, int i)
 {
        return q->write_ptr >= q->read_ptr ?
                (i >= q->read_ptr && i < q->write_ptr) :
@@ -423,8 +434,8 @@ static inline u8 get_cmd_index(struct iwl_queue *q, u32 index)
        return index & (q->n_window - 1);
 }
 
-static inline const char *
-trans_pcie_get_cmd_string(struct iwl_trans_pcie *trans_pcie, u8 cmd)
+static inline const char *get_cmd_string(struct iwl_trans_pcie *trans_pcie,
+                                        u8 cmd)
 {
        if (!trans_pcie->command_names || !trans_pcie->command_names[cmd])
                return "UNKNOWN";
index 41d821fbdb9216e8d4ab9ab2ef3c287a2926cfaa..bb32510fdd62306fed4f3ec867d7d9d16aca3cde 100644 (file)
@@ -76,7 +76,7 @@
  * + A list of pre-allocated SKBs is stored in iwl->rxq->rx_free.  When
  *   iwl->rxq->free_count drops to or below RX_LOW_WATERMARK, work is scheduled
  *   to replenish the iwl->rxq->rx_free.
- * + In iwl_rx_replenish (scheduled) if 'processed' != 'read' then the
+ * + In iwl_pcie_rx_replenish (scheduled) if 'processed' != 'read' then the
  *   iwl->rxq is replenished and the READ INDEX is updated (updating the
  *   'processed' and 'read' driver indexes as well)
  * + A received packet is processed and handed to the kernel network stack,
  *
  * Driver sequence:
  *
- * iwl_rx_queue_alloc()   Allocates rx_free
- * iwl_rx_replenish()     Replenishes rx_free list from rx_used, and calls
- *                            iwl_rx_queue_restock
- * iwl_rx_queue_restock() Moves available buffers from rx_free into Rx
+ * iwl_rxq_alloc()            Allocates rx_free
+ * iwl_pcie_rx_replenish()    Replenishes rx_free list from rx_used, and calls
+ *                            iwl_pcie_rxq_restock
+ * iwl_pcie_rxq_restock()     Moves available buffers from rx_free into Rx
  *                            queue, updates firmware pointers, and updates
  *                            the WRITE index.  If insufficient rx_free buffers
- *                            are available, schedules iwl_rx_replenish
+ *                            are available, schedules iwl_pcie_rx_replenish
  *
  * -- enable interrupts --
- * ISR - iwl_rx()         Detach iwl_rx_mem_buffers from pool up to the
+ * ISR - iwl_rx()             Detach iwl_rx_mem_buffers from pool up to the
  *                            READ INDEX, detaching the SKB from the pool.
  *                            Moves the packet buffer from queue to rx_used.
- *                            Calls iwl_rx_queue_restock to refill any empty
+ *                            Calls iwl_pcie_rxq_restock to refill any empty
  *                            slots.
  * ...
  *
  */
 
-/**
- * iwl_rx_queue_space - Return number of free slots available in queue.
+/*
+ * iwl_rxq_space - Return number of free slots available in queue.
  */
-static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
+static int iwl_rxq_space(const struct iwl_rxq *q)
 {
        int s = q->read - q->write;
        if (s <= 0)
@@ -122,11 +122,28 @@ static int iwl_rx_queue_space(const struct iwl_rx_queue *q)
        return s;
 }
 
-/**
- * iwl_rx_queue_update_write_ptr - Update the write pointer for the RX queue
+/*
+ * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
+ */
+static inline __le32 iwl_pcie_dma_addr2rbd_ptr(dma_addr_t dma_addr)
+{
+       return cpu_to_le32((u32)(dma_addr >> 8));
+}
+
+/*
+ * iwl_pcie_rx_stop - stops the Rx DMA
+ */
+int iwl_pcie_rx_stop(struct iwl_trans *trans)
+{
+       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+       return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
+                                  FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
+}
+
+/*
+ * iwl_pcie_rxq_inc_wr_ptr - Update the write pointer for the RX queue
  */
-void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
-                                  struct iwl_rx_queue *q)
+static void iwl_pcie_rxq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_rxq *q)
 {
        unsigned long flags;
        u32 reg;
@@ -176,16 +193,8 @@ void iwl_rx_queue_update_write_ptr(struct iwl_trans *trans,
        spin_unlock_irqrestore(&q->lock, flags);
 }
 
-/**
- * iwl_dma_addr2rbd_ptr - convert a DMA address to a uCode read buffer ptr
- */
-static inline __le32 iwl_dma_addr2rbd_ptr(dma_addr_t dma_addr)
-{
-       return cpu_to_le32((u32)(dma_addr >> 8));
-}
-
-/**
- * iwl_rx_queue_restock - refill RX queue from pre-allocated pool
+/*
+ * iwl_pcie_rxq_restock - refill RX queue from pre-allocated pool
  *
  * If there are slots in the RX queue that need to be restocked,
  * and we have free pre-allocated buffers, fill the ranks as much
@@ -195,11 +204,10 @@ static inline __le32 iwl_dma_addr2rbd_ptr(dma_addr_t dma_addr)
  * also updates the memory address in the firmware to reference the new
  * target buffer.
  */
-static void iwl_rx_queue_restock(struct iwl_trans *trans)
+static void iwl_pcie_rxq_restock(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct list_head *element;
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
        unsigned long flags;
 
@@ -215,18 +223,18 @@ static void iwl_rx_queue_restock(struct iwl_trans *trans)
                return;
 
        spin_lock_irqsave(&rxq->lock, flags);
-       while ((iwl_rx_queue_space(rxq) > 0) && (rxq->free_count)) {
+       while ((iwl_rxq_space(rxq) > 0) && (rxq->free_count)) {
                /* The overwritten rxb must be a used one */
                rxb = rxq->queue[rxq->write];
                BUG_ON(rxb && rxb->page);
 
                /* Get next free Rx buffer, remove from free list */
-               element = rxq->rx_free.next;
-               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-               list_del(element);
+               rxb = list_first_entry(&rxq->rx_free, struct iwl_rx_mem_buffer,
+                                      list);
+               list_del(&rxb->list);
 
                /* Point to Rx buffer via next RBD in circular buffer */
-               rxq->bd[rxq->write] = iwl_dma_addr2rbd_ptr(rxb->page_dma);
+               rxq->bd[rxq->write] = iwl_pcie_dma_addr2rbd_ptr(rxb->page_dma);
                rxq->queue[rxq->write] = rxb;
                rxq->write = (rxq->write + 1) & RX_QUEUE_MASK;
                rxq->free_count--;
@@ -243,24 +251,23 @@ static void iwl_rx_queue_restock(struct iwl_trans *trans)
                spin_lock_irqsave(&rxq->lock, flags);
                rxq->need_update = 1;
                spin_unlock_irqrestore(&rxq->lock, flags);
-               iwl_rx_queue_update_write_ptr(trans, rxq);
+               iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
        }
 }
 
 /*
- * iwl_rx_allocate - allocate a page for each used RBD
+ * iwl_pcie_rxq_alloc_rbs - allocate a page for each used RBD
  *
  * A used RBD is an Rx buffer that has been given to the stack. To use it again
  * a page must be allocated and the RBD must point to the page. This function
  * doesn't change the HW pointer but handles the list of pages that is used by
- * iwl_rx_queue_restock. The latter function will update the HW to use the newly
+ * iwl_pcie_rxq_restock. The latter function will update the HW to use the newly
  * allocated buffers.
  */
-static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority)
+static void iwl_pcie_rxq_alloc_rbs(struct iwl_trans *trans, gfp_t priority)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct list_head *element;
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
        struct iwl_rx_mem_buffer *rxb;
        struct page *page;
        unsigned long flags;
@@ -308,10 +315,9 @@ static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority)
                        __free_pages(page, trans_pcie->rx_page_order);
                        return;
                }
-               element = rxq->rx_used.next;
-               rxb = list_entry(element, struct iwl_rx_mem_buffer, list);
-               list_del(element);
-
+               rxb = list_first_entry(&rxq->rx_used, struct iwl_rx_mem_buffer,
+                                      list);
+               list_del(&rxb->list);
                spin_unlock_irqrestore(&rxq->lock, flags);
 
                BUG_ON(rxb->page);
@@ -343,47 +349,227 @@ static void iwl_rx_allocate(struct iwl_trans *trans, gfp_t priority)
        }
 }
 
+static void iwl_pcie_rxq_free_rbs(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       int i;
+
+       /* Fill the rx_used queue with _all_ of the Rx buffers */
+       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
+               /* In the reset function, these buffers may have been allocated
+                * to an SKB, so we need to unmap and free potential storage */
+               if (rxq->pool[i].page != NULL) {
+                       dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
+                                      PAGE_SIZE << trans_pcie->rx_page_order,
+                                      DMA_FROM_DEVICE);
+                       __free_pages(rxq->pool[i].page,
+                                    trans_pcie->rx_page_order);
+                       rxq->pool[i].page = NULL;
+               }
+               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
+       }
+}
+
 /*
- * iwl_rx_replenish - Move all used buffers from rx_used to rx_free
+ * iwl_pcie_rx_replenish - Move all used buffers from rx_used to rx_free
  *
  * When moving to rx_free an page is allocated for the slot.
  *
- * Also restock the Rx queue via iwl_rx_queue_restock.
+ * Also restock the Rx queue via iwl_pcie_rxq_restock.
  * This is called as a scheduled work item (except for during initialization)
  */
-void iwl_rx_replenish(struct iwl_trans *trans)
+static void iwl_pcie_rx_replenish(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        unsigned long flags;
 
-       iwl_rx_allocate(trans, GFP_KERNEL);
+       iwl_pcie_rxq_alloc_rbs(trans, GFP_KERNEL);
 
        spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       iwl_rx_queue_restock(trans);
+       iwl_pcie_rxq_restock(trans);
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 }
 
-static void iwl_rx_replenish_now(struct iwl_trans *trans)
+static void iwl_pcie_rx_replenish_now(struct iwl_trans *trans)
 {
-       iwl_rx_allocate(trans, GFP_ATOMIC);
+       iwl_pcie_rxq_alloc_rbs(trans, GFP_ATOMIC);
 
-       iwl_rx_queue_restock(trans);
+       iwl_pcie_rxq_restock(trans);
 }
 
-void iwl_bg_rx_replenish(struct work_struct *data)
+static void iwl_pcie_rx_replenish_work(struct work_struct *data)
 {
        struct iwl_trans_pcie *trans_pcie =
            container_of(data, struct iwl_trans_pcie, rx_replenish);
 
-       iwl_rx_replenish(trans_pcie->trans);
+       iwl_pcie_rx_replenish(trans_pcie->trans);
+}
+
+static int iwl_pcie_rx_alloc(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       struct device *dev = trans->dev;
+
+       memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
+
+       spin_lock_init(&rxq->lock);
+
+       if (WARN_ON(rxq->bd || rxq->rb_stts))
+               return -EINVAL;
+
+       /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
+       rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                                     &rxq->bd_dma, GFP_KERNEL);
+       if (!rxq->bd)
+               goto err_bd;
+
+       /*Allocate the driver's pointer to receive buffer status */
+       rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
+                                          &rxq->rb_stts_dma, GFP_KERNEL);
+       if (!rxq->rb_stts)
+               goto err_rb_stts;
+
+       return 0;
+
+err_rb_stts:
+       dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                         rxq->bd, rxq->bd_dma);
+       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+       rxq->bd = NULL;
+err_bd:
+       return -ENOMEM;
+}
+
+static void iwl_pcie_rx_hw_init(struct iwl_trans *trans, struct iwl_rxq *rxq)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 rb_size;
+       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
+
+       if (trans_pcie->rx_buf_size_8k)
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
+       else
+               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
+
+       /* Stop Rx DMA */
+       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
+
+       /* Reset driver's Rx queue write index */
+       iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
+
+       /* Tell device where to find RBD circular buffer in DRAM */
+       iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
+                          (u32)(rxq->bd_dma >> 8));
+
+       /* Tell device where in DRAM to update its Rx status */
+       iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG,
+                          rxq->rb_stts_dma >> 4);
+
+       /* Enable Rx DMA
+        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
+        *      the credit mechanism in 5000 HW RX FIFO
+        * Direct rx interrupts to hosts
+        * Rx buffer size 4 or 8k
+        * RB timeout 0x10
+        * 256 RBDs
+        */
+       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG,
+                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
+                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
+                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
+                          rb_size|
+                          (RX_RB_TIMEOUT << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
+                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
+
+       /* Set interrupt coalescing timer to default (2048 usecs) */
+       iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
+}
+
+int iwl_pcie_rx_init(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
+
+       int i, err;
+       unsigned long flags;
+
+       if (!rxq->bd) {
+               err = iwl_pcie_rx_alloc(trans);
+               if (err)
+                       return err;
+       }
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       INIT_LIST_HEAD(&rxq->rx_free);
+       INIT_LIST_HEAD(&rxq->rx_used);
+
+       INIT_WORK(&trans_pcie->rx_replenish,
+                 iwl_pcie_rx_replenish_work);
+
+       iwl_pcie_rxq_free_rbs(trans);
+
+       for (i = 0; i < RX_QUEUE_SIZE; i++)
+               rxq->queue[i] = NULL;
+
+       /* Set us so that we have processed and used all buffers, but have
+        * not restocked the Rx queue with fresh buffers */
+       rxq->read = rxq->write = 0;
+       rxq->write_actual = 0;
+       rxq->free_count = 0;
+       spin_unlock_irqrestore(&rxq->lock, flags);
+
+       iwl_pcie_rx_replenish(trans);
+
+       iwl_pcie_rx_hw_init(trans, rxq);
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+       rxq->need_update = 1;
+       iwl_pcie_rxq_inc_wr_ptr(trans, rxq);
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       return 0;
+}
+
+void iwl_pcie_rx_free(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       unsigned long flags;
+
+       /*if rxq->bd is NULL, it means that nothing has been allocated,
+        * exit now */
+       if (!rxq->bd) {
+               IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
+               return;
+       }
+
+       spin_lock_irqsave(&rxq->lock, flags);
+       iwl_pcie_rxq_free_rbs(trans);
+       spin_unlock_irqrestore(&rxq->lock, flags);
+
+       dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
+                         rxq->bd, rxq->bd_dma);
+       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
+       rxq->bd = NULL;
+
+       if (rxq->rb_stts)
+               dma_free_coherent(trans->dev,
+                                 sizeof(struct iwl_rb_status),
+                                 rxq->rb_stts, rxq->rb_stts_dma);
+       else
+               IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
+       memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
+       rxq->rb_stts = NULL;
 }
 
-static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
+static void iwl_pcie_rx_handle_rb(struct iwl_trans *trans,
                                struct iwl_rx_mem_buffer *rxb)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
+       struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
        unsigned long flags;
        bool page_stolen = false;
        int max_len = PAGE_SIZE << trans_pcie->rx_page_order;
@@ -413,8 +599,7 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
                        break;
 
                IWL_DEBUG_RX(trans, "cmd at offset %d: %s (0x%.2x)\n",
-                       rxcb._offset,
-                       trans_pcie_get_cmd_string(trans_pcie, pkt->hdr.cmd),
+                       rxcb._offset, get_cmd_string(trans_pcie, pkt->hdr.cmd),
                        pkt->hdr.cmd);
 
                len = le32_to_cpu(pkt->len_n_flags) & FH_RSCSR_FRAME_SIZE_MSK;
@@ -446,7 +631,7 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
                cmd_index = get_cmd_index(&txq->q, index);
 
                if (reclaim) {
-                       struct iwl_pcie_tx_queue_entry *ent;
+                       struct iwl_pcie_txq_entry *ent;
                        ent = &txq->entries[cmd_index];
                        cmd = ent->copy_cmd;
                        WARN_ON_ONCE(!cmd && ent->meta.flags & CMD_WANT_HCMD);
@@ -460,6 +645,9 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
                        /* The original command isn't needed any more */
                        kfree(txq->entries[cmd_index].copy_cmd);
                        txq->entries[cmd_index].copy_cmd = NULL;
+                       /* nor is the duplicated part of the command */
+                       kfree(txq->entries[cmd_index].free_buf);
+                       txq->entries[cmd_index].free_buf = NULL;
                }
 
                /*
@@ -473,7 +661,7 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
                         * iwl_trans_send_cmd()
                         * as we reclaim the driver command queue */
                        if (!rxcb._page_stolen)
-                               iwl_tx_cmd_complete(trans, &rxcb, err);
+                               iwl_pcie_hcmd_complete(trans, &rxcb, err);
                        else
                                IWL_WARN(trans, "Claim null rxb?\n");
                }
@@ -515,17 +703,13 @@ static void iwl_rx_handle_rxbuf(struct iwl_trans *trans,
        spin_unlock_irqrestore(&rxq->lock, flags);
 }
 
-/**
- * iwl_rx_handle - Main entry function for receiving responses from uCode
- *
- * Uses the priv->rx_handlers callback function array to invoke
- * the appropriate handlers, including command responses,
- * frame-received notifications, and other notifications.
+/*
+ * iwl_pcie_rx_handle - Main entry function for receiving responses from fw
  */
-static void iwl_rx_handle(struct iwl_trans *trans)
+static void iwl_pcie_rx_handle(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
        u32 r, i;
        u8 fill_rx = 0;
        u32 count = 8;
@@ -556,7 +740,7 @@ static void iwl_rx_handle(struct iwl_trans *trans)
 
                IWL_DEBUG_RX(trans, "rxbuf: HW = %d, SW = %d (%p)\n",
                             r, i, rxb);
-               iwl_rx_handle_rxbuf(trans, rxb);
+               iwl_pcie_rx_handle_rb(trans, rxb);
 
                i = (i + 1) & RX_QUEUE_MASK;
                /* If there are a lot of unused frames,
@@ -565,7 +749,7 @@ static void iwl_rx_handle(struct iwl_trans *trans)
                        count++;
                        if (count >= 8) {
                                rxq->read = i;
-                               iwl_rx_replenish_now(trans);
+                               iwl_pcie_rx_replenish_now(trans);
                                count = 0;
                        }
                }
@@ -574,39 +758,41 @@ static void iwl_rx_handle(struct iwl_trans *trans)
        /* Backtrack one entry */
        rxq->read = i;
        if (fill_rx)
-               iwl_rx_replenish_now(trans);
+               iwl_pcie_rx_replenish_now(trans);
        else
-               iwl_rx_queue_restock(trans);
+               iwl_pcie_rxq_restock(trans);
 }
 
-/**
- * iwl_irq_handle_error - called for HW or SW error interrupt from card
+/*
+ * iwl_pcie_irq_handle_error - called for HW or SW error interrupt from card
  */
-static void iwl_irq_handle_error(struct iwl_trans *trans)
+static void iwl_pcie_irq_handle_error(struct iwl_trans *trans)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
        /* W/A for WiFi/WiMAX coex and WiMAX own the RF */
        if (trans->cfg->internal_wimax_coex &&
            (!(iwl_read_prph(trans, APMG_CLK_CTRL_REG) &
                             APMS_CLK_VAL_MRB_FUNC_MODE) ||
             (iwl_read_prph(trans, APMG_PS_CTRL_REG) &
                            APMG_PS_CTRL_VAL_RESET_REQ))) {
-               struct iwl_trans_pcie *trans_pcie =
-                       IWL_TRANS_GET_PCIE_TRANS(trans);
-
                clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
                iwl_op_mode_wimax_active(trans->op_mode);
-               wake_up(&trans->wait_command_queue);
+               wake_up(&trans_pcie->wait_command_queue);
                return;
        }
 
-       iwl_dump_csr(trans);
-       iwl_dump_fh(trans, NULL);
+       iwl_pcie_dump_csr(trans);
+       iwl_pcie_dump_fh(trans, NULL);
+
+       set_bit(STATUS_FW_ERROR, &trans_pcie->status);
+       clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
+       wake_up(&trans_pcie->wait_command_queue);
 
        iwl_op_mode_nic_error(trans->op_mode);
 }
 
-/* tasklet for iwlagn interrupt */
-void iwl_irq_tasklet(struct iwl_trans *trans)
+void iwl_pcie_tasklet(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        struct isr_statistics *isr_stats = &trans_pcie->isr_stats;
@@ -658,7 +844,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
                iwl_disable_interrupts(trans);
 
                isr_stats->hw++;
-               iwl_irq_handle_error(trans);
+               iwl_pcie_irq_handle_error(trans);
 
                handled |= CSR_INT_BIT_HW_ERR;
 
@@ -695,6 +881,16 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
                isr_stats->rfkill++;
 
                iwl_op_mode_hw_rf_kill(trans->op_mode, hw_rfkill);
+               if (hw_rfkill) {
+                       set_bit(STATUS_RFKILL, &trans_pcie->status);
+                       if (test_and_clear_bit(STATUS_HCMD_ACTIVE,
+                                              &trans_pcie->status))
+                               IWL_DEBUG_RF_KILL(trans,
+                                                 "Rfkill while SYNC HCMD in flight\n");
+                       wake_up(&trans_pcie->wait_command_queue);
+               } else {
+                       clear_bit(STATUS_RFKILL, &trans_pcie->status);
+               }
 
                handled |= CSR_INT_BIT_RF_KILL;
        }
@@ -711,17 +907,16 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
                IWL_ERR(trans, "Microcode SW error detected. "
                        " Restarting 0x%X.\n", inta);
                isr_stats->sw++;
-               iwl_irq_handle_error(trans);
+               iwl_pcie_irq_handle_error(trans);
                handled |= CSR_INT_BIT_SW_ERR;
        }
 
        /* uCode wakes up after power-down sleep */
        if (inta & CSR_INT_BIT_WAKEUP) {
                IWL_DEBUG_ISR(trans, "Wakeup interrupt\n");
-               iwl_rx_queue_update_write_ptr(trans, &trans_pcie->rxq);
+               iwl_pcie_rxq_inc_wr_ptr(trans, &trans_pcie->rxq);
                for (i = 0; i < trans->cfg->base_params->num_of_queues; i++)
-                       iwl_txq_update_write_ptr(trans,
-                                                &trans_pcie->txq[i]);
+                       iwl_pcie_txq_inc_wr_ptr(trans, &trans_pcie->txq[i]);
 
                isr_stats->wakeup++;
 
@@ -759,7 +954,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
                iwl_write8(trans, CSR_INT_PERIODIC_REG,
                            CSR_INT_PERIODIC_DIS);
 
-               iwl_rx_handle(trans);
+               iwl_pcie_rx_handle(trans);
 
                /*
                 * Enable periodic interrupt in 8 msec only if we received
@@ -817,7 +1012,7 @@ void iwl_irq_tasklet(struct iwl_trans *trans)
 #define ICT_COUNT      (ICT_SIZE / sizeof(u32))
 
 /* Free dram table */
-void iwl_free_isr_ict(struct iwl_trans *trans)
+void iwl_pcie_free_ict(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
@@ -830,13 +1025,12 @@ void iwl_free_isr_ict(struct iwl_trans *trans)
        }
 }
 
-
 /*
  * allocate dram shared table, it is an aligned memory
  * block of ICT_SIZE.
  * also reset all data related to ICT table interrupt.
  */
-int iwl_alloc_isr_ict(struct iwl_trans *trans)
+int iwl_pcie_alloc_ict(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
@@ -849,7 +1043,7 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans)
 
        /* just an API sanity check ... it is guaranteed to be aligned */
        if (WARN_ON(trans_pcie->ict_tbl_dma & (ICT_SIZE - 1))) {
-               iwl_free_isr_ict(trans);
+               iwl_pcie_free_ict(trans);
                return -EINVAL;
        }
 
@@ -870,7 +1064,7 @@ int iwl_alloc_isr_ict(struct iwl_trans *trans)
 /* Device is going up inform it about using ICT interrupt table,
  * also we need to tell the driver to start using ICT interrupt.
  */
-void iwl_reset_ict(struct iwl_trans *trans)
+void iwl_pcie_reset_ict(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        u32 val;
@@ -900,7 +1094,7 @@ void iwl_reset_ict(struct iwl_trans *trans)
 }
 
 /* Device is going down disable ict interrupt usage */
-void iwl_disable_ict(struct iwl_trans *trans)
+void iwl_pcie_disable_ict(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        unsigned long flags;
@@ -911,7 +1105,7 @@ void iwl_disable_ict(struct iwl_trans *trans)
 }
 
 /* legacy (non-ICT) ISR. Assumes that trans_pcie->irq_lock is held */
-static irqreturn_t iwl_isr(int irq, void *data)
+static irqreturn_t iwl_pcie_isr(int irq, void *data)
 {
        struct iwl_trans *trans = data;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -958,7 +1152,7 @@ static irqreturn_t iwl_isr(int irq, void *data)
 #endif
 
        trans_pcie->inta |= inta;
-       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       /* iwl_pcie_tasklet() will service interrupts and re-enable them */
        if (likely(inta))
                tasklet_schedule(&trans_pcie->irq_tasklet);
        else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
@@ -983,7 +1177,7 @@ none:
  * the interrupt we need to service, driver will set the entries back to 0 and
  * set index.
  */
-irqreturn_t iwl_isr_ict(int irq, void *data)
+irqreturn_t iwl_pcie_isr_ict(int irq, void *data)
 {
        struct iwl_trans *trans = data;
        struct iwl_trans_pcie *trans_pcie;
@@ -1003,14 +1197,13 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
         * use legacy interrupt.
         */
        if (unlikely(!trans_pcie->use_ict)) {
-               irqreturn_t ret = iwl_isr(irq, data);
+               irqreturn_t ret = iwl_pcie_isr(irq, data);
                spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
                return ret;
        }
 
        trace_iwlwifi_dev_irq(trans->dev);
 
-
        /* Disable (but don't clear!) interrupts here to avoid
         * back-to-back ISRs and sporadic interrupts from our NIC.
         * If we have something to service, the tasklet will re-enable ints.
@@ -1019,7 +1212,6 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
        inta_mask = iwl_read32(trans, CSR_INT_MASK);  /* just for debug */
        iwl_write32(trans, CSR_INT_MASK, 0x00000000);
 
-
        /* Ignore interrupt if there's nothing in NIC to service.
         * This may be due to IRQ shared with another device,
         * or due to sporadic interrupts thrown from our NIC. */
@@ -1068,7 +1260,7 @@ irqreturn_t iwl_isr_ict(int irq, void *data)
        inta &= trans_pcie->inta_mask;
        trans_pcie->inta |= inta;
 
-       /* iwl_irq_tasklet() will service interrupts and re-enable them */
+       /* iwl_pcie_tasklet() will service interrupts and re-enable them */
        if (likely(inta))
                tasklet_schedule(&trans_pcie->irq_tasklet);
        else if (test_bit(STATUS_INT_ENABLED, &trans_pcie->status) &&
index f95d88df7772014a430f620c889303bf135ff9c3..f6c21e7edaf2eccd13fe5adb0a27f7f0d8359621 100644 (file)
 #include "iwl-prph.h"
 #include "iwl-agn-hw.h"
 #include "internal.h"
-/* FIXME: need to abstract out TX command (once we know what it looks like) */
-#include "dvm/commands.h"
 
-#define SCD_QUEUECHAIN_SEL_ALL(trans, trans_pcie)      \
-       (((1<<trans->cfg->base_params->num_of_queues) - 1) &\
-       (~(1<<(trans_pcie)->cmd_queue)))
-
-static int iwl_trans_rx_alloc(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       struct device *dev = trans->dev;
-
-       memset(&trans_pcie->rxq, 0, sizeof(trans_pcie->rxq));
-
-       spin_lock_init(&rxq->lock);
-
-       if (WARN_ON(rxq->bd || rxq->rb_stts))
-               return -EINVAL;
-
-       /* Allocate the circular buffer of Read Buffer Descriptors (RBDs) */
-       rxq->bd = dma_zalloc_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                                     &rxq->bd_dma, GFP_KERNEL);
-       if (!rxq->bd)
-               goto err_bd;
-
-       /*Allocate the driver's pointer to receive buffer status */
-       rxq->rb_stts = dma_zalloc_coherent(dev, sizeof(*rxq->rb_stts),
-                                          &rxq->rb_stts_dma, GFP_KERNEL);
-       if (!rxq->rb_stts)
-               goto err_rb_stts;
-
-       return 0;
-
-err_rb_stts:
-       dma_free_coherent(dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                         rxq->bd, rxq->bd_dma);
-       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
-       rxq->bd = NULL;
-err_bd:
-       return -ENOMEM;
-}
-
-static void iwl_trans_rxq_free_rx_bufs(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       int i;
-
-       /* Fill the rx_used queue with _all_ of the Rx buffers */
-       for (i = 0; i < RX_FREE_BUFFERS + RX_QUEUE_SIZE; i++) {
-               /* In the reset function, these buffers may have been allocated
-                * to an SKB, so we need to unmap and free potential storage */
-               if (rxq->pool[i].page != NULL) {
-                       dma_unmap_page(trans->dev, rxq->pool[i].page_dma,
-                                      PAGE_SIZE << trans_pcie->rx_page_order,
-                                      DMA_FROM_DEVICE);
-                       __free_pages(rxq->pool[i].page,
-                                    trans_pcie->rx_page_order);
-                       rxq->pool[i].page = NULL;
-               }
-               list_add_tail(&rxq->pool[i].list, &rxq->rx_used);
-       }
-}
-
-static void iwl_trans_rx_hw_init(struct iwl_trans *trans,
-                                struct iwl_rx_queue *rxq)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       u32 rb_size;
-       const u32 rfdnlog = RX_QUEUE_SIZE_LOG; /* 256 RBDs */
-       u32 rb_timeout = RX_RB_TIMEOUT; /* FIXME: RX_RB_TIMEOUT for all devices? */
-
-       if (trans_pcie->rx_buf_size_8k)
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_8K;
-       else
-               rb_size = FH_RCSR_RX_CONFIG_REG_VAL_RB_SIZE_4K;
-
-       /* Stop Rx DMA */
-       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-
-       /* Reset driver's Rx queue write index */
-       iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_WPTR_REG, 0);
-
-       /* Tell device where to find RBD circular buffer in DRAM */
-       iwl_write_direct32(trans, FH_RSCSR_CHNL0_RBDCB_BASE_REG,
-                          (u32)(rxq->bd_dma >> 8));
-
-       /* Tell device where in DRAM to update its Rx status */
-       iwl_write_direct32(trans, FH_RSCSR_CHNL0_STTS_WPTR_REG,
-                          rxq->rb_stts_dma >> 4);
-
-       /* Enable Rx DMA
-        * FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY is set because of HW bug in
-        *      the credit mechanism in 5000 HW RX FIFO
-        * Direct rx interrupts to hosts
-        * Rx buffer size 4 or 8k
-        * RB timeout 0x10
-        * 256 RBDs
-        */
-       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG,
-                          FH_RCSR_RX_CONFIG_CHNL_EN_ENABLE_VAL |
-                          FH_RCSR_CHNL0_RX_IGNORE_RXF_EMPTY |
-                          FH_RCSR_CHNL0_RX_CONFIG_IRQ_DEST_INT_HOST_VAL |
-                          rb_size|
-                          (rb_timeout << FH_RCSR_RX_CONFIG_REG_IRQ_RBTH_POS)|
-                          (rfdnlog << FH_RCSR_RX_CONFIG_RBDCB_SIZE_POS));
-
-       /* Set interrupt coalescing timer to default (2048 usecs) */
-       iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_TIMEOUT_DEF);
-}
-
-static int iwl_rx_init(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-
-       int i, err;
-       unsigned long flags;
-
-       if (!rxq->bd) {
-               err = iwl_trans_rx_alloc(trans);
-               if (err)
-                       return err;
-       }
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       INIT_LIST_HEAD(&rxq->rx_free);
-       INIT_LIST_HEAD(&rxq->rx_used);
-
-       iwl_trans_rxq_free_rx_bufs(trans);
-
-       for (i = 0; i < RX_QUEUE_SIZE; i++)
-               rxq->queue[i] = NULL;
-
-       /* Set us so that we have processed and used all buffers, but have
-        * not restocked the Rx queue with fresh buffers */
-       rxq->read = rxq->write = 0;
-       rxq->write_actual = 0;
-       rxq->free_count = 0;
-       spin_unlock_irqrestore(&rxq->lock, flags);
-
-       iwl_rx_replenish(trans);
-
-       iwl_trans_rx_hw_init(trans, rxq);
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       rxq->need_update = 1;
-       iwl_rx_queue_update_write_ptr(trans, rxq);
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       return 0;
-}
-
-static void iwl_trans_pcie_rx_free(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
-       unsigned long flags;
-
-       /*if rxq->bd is NULL, it means that nothing has been allocated,
-        * exit now */
-       if (!rxq->bd) {
-               IWL_DEBUG_INFO(trans, "Free NULL rx context\n");
-               return;
-       }
-
-       spin_lock_irqsave(&rxq->lock, flags);
-       iwl_trans_rxq_free_rx_bufs(trans);
-       spin_unlock_irqrestore(&rxq->lock, flags);
-
-       dma_free_coherent(trans->dev, sizeof(__le32) * RX_QUEUE_SIZE,
-                         rxq->bd, rxq->bd_dma);
-       memset(&rxq->bd_dma, 0, sizeof(rxq->bd_dma));
-       rxq->bd = NULL;
-
-       if (rxq->rb_stts)
-               dma_free_coherent(trans->dev,
-                                 sizeof(struct iwl_rb_status),
-                                 rxq->rb_stts, rxq->rb_stts_dma);
-       else
-               IWL_DEBUG_INFO(trans, "Free rxq->rb_stts which is NULL\n");
-       memset(&rxq->rb_stts_dma, 0, sizeof(rxq->rb_stts_dma));
-       rxq->rb_stts = NULL;
-}
-
-static int iwl_trans_rx_stop(struct iwl_trans *trans)
-{
-
-       /* stop Rx DMA */
-       iwl_write_direct32(trans, FH_MEM_RCSR_CHNL0_CONFIG_REG, 0);
-       return iwl_poll_direct_bit(trans, FH_MEM_RSSR_RX_STATUS_REG,
-                                  FH_RSSR_CHNL0_RX_STATUS_CHNL_IDLE, 1000);
-}
-
-static int iwlagn_alloc_dma_ptr(struct iwl_trans *trans,
-                               struct iwl_dma_ptr *ptr, size_t size)
-{
-       if (WARN_ON(ptr->addr))
-               return -EINVAL;
-
-       ptr->addr = dma_alloc_coherent(trans->dev, size,
-                                      &ptr->dma, GFP_KERNEL);
-       if (!ptr->addr)
-               return -ENOMEM;
-       ptr->size = size;
-       return 0;
-}
-
-static void iwlagn_free_dma_ptr(struct iwl_trans *trans,
-                               struct iwl_dma_ptr *ptr)
-{
-       if (unlikely(!ptr->addr))
-               return;
-
-       dma_free_coherent(trans->dev, ptr->size, ptr->addr, ptr->dma);
-       memset(ptr, 0, sizeof(*ptr));
-}
-
-static void iwl_trans_pcie_queue_stuck_timer(unsigned long data)
-{
-       struct iwl_tx_queue *txq = (void *)data;
-       struct iwl_queue *q = &txq->q;
-       struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
-       struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
-       u32 scd_sram_addr = trans_pcie->scd_base_addr +
-                               SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
-       u8 buf[16];
-       int i;
-
-       spin_lock(&txq->lock);
-       /* check if triggered erroneously */
-       if (txq->q.read_ptr == txq->q.write_ptr) {
-               spin_unlock(&txq->lock);
-               return;
-       }
-       spin_unlock(&txq->lock);
-
-       IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
-               jiffies_to_msecs(trans_pcie->wd_timeout));
-       IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
-               txq->q.read_ptr, txq->q.write_ptr);
-
-       iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
-
-       iwl_print_hex_error(trans, buf, sizeof(buf));
-
-       for (i = 0; i < FH_TCSR_CHNL_NUM; i++)
-               IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", i,
-                       iwl_read_direct32(trans, FH_TX_TRB_REG(i)));
-
-       for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
-               u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(i));
-               u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
-               bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
-               u32 tbl_dw =
-                       iwl_read_targ_mem(trans,
-                                         trans_pcie->scd_base_addr +
-                                         SCD_TRANS_TBL_OFFSET_QUEUE(i));
-
-               if (i & 0x1)
-                       tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
-               else
-                       tbl_dw = tbl_dw & 0x0000FFFF;
-
-               IWL_ERR(trans,
-                       "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
-                       i, active ? "" : "in", fifo, tbl_dw,
-                       iwl_read_prph(trans,
-                                     SCD_QUEUE_RDPTR(i)) & (txq->q.n_bd - 1),
-                       iwl_read_prph(trans, SCD_QUEUE_WRPTR(i)));
-       }
-
-       for (i = q->read_ptr; i != q->write_ptr;
-            i = iwl_queue_inc_wrap(i, q->n_bd)) {
-               struct iwl_tx_cmd *tx_cmd =
-                       (struct iwl_tx_cmd *)txq->entries[i].cmd->payload;
-               IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
-                       get_unaligned_le32(&tx_cmd->scratch));
-       }
-
-       iwl_op_mode_nic_error(trans->op_mode);
-}
-
-static int iwl_trans_txq_alloc(struct iwl_trans *trans,
-                              struct iwl_tx_queue *txq, int slots_num,
-                              u32 txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
-       int i;
-
-       if (WARN_ON(txq->entries || txq->tfds))
-               return -EINVAL;
-
-       setup_timer(&txq->stuck_timer, iwl_trans_pcie_queue_stuck_timer,
-                   (unsigned long)txq);
-       txq->trans_pcie = trans_pcie;
-
-       txq->q.n_window = slots_num;
-
-       txq->entries = kcalloc(slots_num,
-                              sizeof(struct iwl_pcie_tx_queue_entry),
-                              GFP_KERNEL);
-
-       if (!txq->entries)
-               goto error;
-
-       if (txq_id == trans_pcie->cmd_queue)
-               for (i = 0; i < slots_num; i++) {
-                       txq->entries[i].cmd =
-                               kmalloc(sizeof(struct iwl_device_cmd),
-                                       GFP_KERNEL);
-                       if (!txq->entries[i].cmd)
-                               goto error;
-               }
-
-       /* Circular buffer of transmit frame descriptors (TFDs),
-        * shared with device */
-       txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz,
-                                      &txq->q.dma_addr, GFP_KERNEL);
-       if (!txq->tfds) {
-               IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
-               goto error;
-       }
-       txq->q.id = txq_id;
-
-       return 0;
-error:
-       if (txq->entries && txq_id == trans_pcie->cmd_queue)
-               for (i = 0; i < slots_num; i++)
-                       kfree(txq->entries[i].cmd);
-       kfree(txq->entries);
-       txq->entries = NULL;
-
-       return -ENOMEM;
-
-}
-
-static int iwl_trans_txq_init(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-                             int slots_num, u32 txq_id)
-{
-       int ret;
-
-       txq->need_update = 0;
-
-       /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
-        * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
-       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
-
-       /* Initialize queue's high/low-water marks, and head/tail indexes */
-       ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
-                       txq_id);
-       if (ret)
-               return ret;
-
-       spin_lock_init(&txq->lock);
-
-       /*
-        * Tell nic where to find circular buffer of Tx Frame Descriptors for
-        * given Tx queue, and enable the DMA channel used for that queue.
-        * Circular buffer (TFD queue in DRAM) physical base address */
-       iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
-                            txq->q.dma_addr >> 8);
-
-       return 0;
-}
-
-/**
- * iwl_tx_queue_unmap -  Unmap any remaining DMA mappings and free skb's
- */
-static void iwl_tx_queue_unmap(struct iwl_trans *trans, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-       enum dma_data_direction dma_dir;
-
-       if (!q->n_bd)
-               return;
-
-       /* In the command queue, all the TBs are mapped as BIDI
-        * so unmap them as such.
-        */
-       if (txq_id == trans_pcie->cmd_queue)
-               dma_dir = DMA_BIDIRECTIONAL;
-       else
-               dma_dir = DMA_TO_DEVICE;
-
-       spin_lock_bh(&txq->lock);
-       while (q->write_ptr != q->read_ptr) {
-               iwl_txq_free_tfd(trans, txq, dma_dir);
-               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
-       }
-       spin_unlock_bh(&txq->lock);
-}
-
-/**
- * iwl_tx_queue_free - Deallocate DMA queue.
- * @txq: Transmit queue to deallocate.
- *
- * Empty queue by removing and destroying all BD's.
- * Free all buffers.
- * 0-fill, but do not free "txq" descriptor structure.
- */
-static void iwl_tx_queue_free(struct iwl_trans *trans, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct device *dev = trans->dev;
-       int i;
-
-       if (WARN_ON(!txq))
-               return;
-
-       iwl_tx_queue_unmap(trans, txq_id);
-
-       /* De-alloc array of command/tx buffers */
-       if (txq_id == trans_pcie->cmd_queue)
-               for (i = 0; i < txq->q.n_window; i++) {
-                       kfree(txq->entries[i].cmd);
-                       kfree(txq->entries[i].copy_cmd);
-               }
-
-       /* De-alloc circular buffer of TFDs */
-       if (txq->q.n_bd) {
-               dma_free_coherent(dev, sizeof(struct iwl_tfd) *
-                                 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
-               memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
-       }
-
-       kfree(txq->entries);
-       txq->entries = NULL;
-
-       del_timer_sync(&txq->stuck_timer);
-
-       /* 0-fill queue descriptor structure */
-       memset(txq, 0, sizeof(*txq));
-}
-
-/**
- * iwl_trans_tx_free - Free TXQ Context
- *
- * Destroy all TX DMA queues and structures
- */
-static void iwl_trans_pcie_tx_free(struct iwl_trans *trans)
-{
-       int txq_id;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       /* Tx queues */
-       if (trans_pcie->txq) {
-               for (txq_id = 0;
-                    txq_id < trans->cfg->base_params->num_of_queues; txq_id++)
-                       iwl_tx_queue_free(trans, txq_id);
-       }
-
-       kfree(trans_pcie->txq);
-       trans_pcie->txq = NULL;
-
-       iwlagn_free_dma_ptr(trans, &trans_pcie->kw);
-
-       iwlagn_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls);
-}
-
-/**
- * iwl_trans_tx_alloc - allocate TX context
- * Allocate all Tx DMA structures and initialize them
- *
- * @param priv
- * @return error code
- */
-static int iwl_trans_tx_alloc(struct iwl_trans *trans)
-{
-       int ret;
-       int txq_id, slots_num;
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       u16 scd_bc_tbls_size = trans->cfg->base_params->num_of_queues *
-                       sizeof(struct iwlagn_scd_bc_tbl);
-
-       /*It is not allowed to alloc twice, so warn when this happens.
-        * We cannot rely on the previous allocation, so free and fail */
-       if (WARN_ON(trans_pcie->txq)) {
-               ret = -EINVAL;
-               goto error;
-       }
-
-       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls,
-                                  scd_bc_tbls_size);
-       if (ret) {
-               IWL_ERR(trans, "Scheduler BC Table allocation failed\n");
-               goto error;
-       }
-
-       /* Alloc keep-warm buffer */
-       ret = iwlagn_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE);
-       if (ret) {
-               IWL_ERR(trans, "Keep Warm allocation failed\n");
-               goto error;
-       }
-
-       trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues,
-                                 sizeof(struct iwl_tx_queue), GFP_KERNEL);
-       if (!trans_pcie->txq) {
-               IWL_ERR(trans, "Not enough memory for txq\n");
-               ret = ENOMEM;
-               goto error;
-       }
-
-       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
-       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
-            txq_id++) {
-               slots_num = (txq_id == trans_pcie->cmd_queue) ?
-                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               ret = iwl_trans_txq_alloc(trans, &trans_pcie->txq[txq_id],
-                                         slots_num, txq_id);
-               if (ret) {
-                       IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
-                       goto error;
-               }
-       }
-
-       return 0;
-
-error:
-       iwl_trans_pcie_tx_free(trans);
-
-       return ret;
-}
-static int iwl_tx_init(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       int ret;
-       int txq_id, slots_num;
-       unsigned long flags;
-       bool alloc = false;
-
-       if (!trans_pcie->txq) {
-               ret = iwl_trans_tx_alloc(trans);
-               if (ret)
-                       goto error;
-               alloc = true;
-       }
-
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       /* Turn off all Tx DMA fifos */
-       iwl_write_prph(trans, SCD_TXFACT, 0);
-
-       /* Tell NIC where to find the "keep warm" buffer */
-       iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
-                          trans_pcie->kw.dma >> 4);
-
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
-       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
-            txq_id++) {
-               slots_num = (txq_id == trans_pcie->cmd_queue) ?
-                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
-               ret = iwl_trans_txq_init(trans, &trans_pcie->txq[txq_id],
-                                        slots_num, txq_id);
-               if (ret) {
-                       IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
-                       goto error;
-               }
-       }
-
-       return 0;
-error:
-       /*Upon error, free only if we allocated something */
-       if (alloc)
-               iwl_trans_pcie_tx_free(trans);
-       return ret;
-}
-
-static void iwl_set_pwr_vmain(struct iwl_trans *trans)
+static void iwl_pcie_set_pwr_vmain(struct iwl_trans *trans)
 {
 /*
  * (for documentation purposes)
@@ -673,18 +97,11 @@ static void iwl_set_pwr_vmain(struct iwl_trans *trans)
 #define PCI_CFG_LINK_CTRL_VAL_L0S_EN   0x01
 #define PCI_CFG_LINK_CTRL_VAL_L1_EN    0x02
 
-static u16 iwl_pciexp_link_ctrl(struct iwl_trans *trans)
+static void iwl_pcie_apm_config(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       u16 pci_lnk_ctl;
-
-       pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL,
-                                 &pci_lnk_ctl);
-       return pci_lnk_ctl;
-}
+       u16 lctl;
 
-static void iwl_apm_config(struct iwl_trans *trans)
-{
        /*
         * HW bug W/A for instability in PCIe bus L0S->L1 transition.
         * Check if BIOS (or OS) enabled L1-ASPM on this device.
@@ -693,29 +110,27 @@ static void iwl_apm_config(struct iwl_trans *trans)
         * If not (unlikely), enable L0S, so there is at least some
         *    power savings, even without L1.
         */
-       u16 lctl = iwl_pciexp_link_ctrl(trans);
+       pcie_capability_read_word(trans_pcie->pci_dev, PCI_EXP_LNKCTL, &lctl);
 
        if ((lctl & PCI_CFG_LINK_CTRL_VAL_L1_EN) ==
                                PCI_CFG_LINK_CTRL_VAL_L1_EN) {
                /* L1-ASPM enabled; disable(!) L0S */
                iwl_set_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-               dev_printk(KERN_INFO, trans->dev,
-                          "L1 Enabled; Disabling L0S\n");
+               dev_info(trans->dev, "L1 Enabled; Disabling L0S\n");
        } else {
                /* L1-ASPM disabled; enable(!) L0S */
                iwl_clear_bit(trans, CSR_GIO_REG, CSR_GIO_REG_VAL_L0S_ENABLED);
-               dev_printk(KERN_INFO, trans->dev,
-                          "L1 Disabled; Enabling L0S\n");
+               dev_info(trans->dev, "L1 Disabled; Enabling L0S\n");
        }
        trans->pm_support = !(lctl & PCI_CFG_LINK_CTRL_VAL_L0S_EN);
 }
 
 /*
  * Start up NIC's basic functionality after it has been reset
- * (e.g. after platform boot, or shutdown via iwl_apm_stop())
+ * (e.g. after platform boot, or shutdown via iwl_pcie_apm_stop())
  * NOTE:  This does not load uCode nor start the embedded processor
  */
-static int iwl_apm_init(struct iwl_trans *trans)
+static int iwl_pcie_apm_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret = 0;
@@ -747,7 +162,7 @@ static int iwl_apm_init(struct iwl_trans *trans)
        iwl_set_bit(trans, CSR_HW_IF_CONFIG_REG,
                    CSR_HW_IF_CONFIG_REG_BIT_HAP_WAKE_L1A);
 
-       iwl_apm_config(trans);
+       iwl_pcie_apm_config(trans);
 
        /* Configure analog phase-lock-loop before activating to D0A */
        if (trans->cfg->base_params->pll_cfg_val)
@@ -793,7 +208,7 @@ out:
        return ret;
 }
 
-static int iwl_apm_stop_master(struct iwl_trans *trans)
+static int iwl_pcie_apm_stop_master(struct iwl_trans *trans)
 {
        int ret = 0;
 
@@ -811,7 +226,7 @@ static int iwl_apm_stop_master(struct iwl_trans *trans)
        return ret;
 }
 
-static void iwl_apm_stop(struct iwl_trans *trans)
+static void iwl_pcie_apm_stop(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        IWL_DEBUG_INFO(trans, "Stop card, put in low power state\n");
@@ -819,7 +234,7 @@ static void iwl_apm_stop(struct iwl_trans *trans)
        clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
 
        /* Stop device's DMA activity */
-       iwl_apm_stop_master(trans);
+       iwl_pcie_apm_stop_master(trans);
 
        /* Reset the entire device */
        iwl_set_bit(trans, CSR_RESET, CSR_RESET_REG_FLAG_SW_RESET);
@@ -834,29 +249,29 @@ static void iwl_apm_stop(struct iwl_trans *trans)
                      CSR_GP_CNTRL_REG_FLAG_INIT_DONE);
 }
 
-static int iwl_nic_init(struct iwl_trans *trans)
+static int iwl_pcie_nic_init(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        unsigned long flags;
 
        /* nic_init */
        spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-       iwl_apm_init(trans);
+       iwl_pcie_apm_init(trans);
 
        /* Set interrupt coalescing calibration timer to default (512 usecs) */
        iwl_write8(trans, CSR_INT_COALESCING, IWL_HOST_INT_CALIB_TIMEOUT_DEF);
 
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
-       iwl_set_pwr_vmain(trans);
+       iwl_pcie_set_pwr_vmain(trans);
 
        iwl_op_mode_nic_config(trans->op_mode);
 
        /* Allocate the RX queue, or reset if it is already allocated */
-       iwl_rx_init(trans);
+       iwl_pcie_rx_init(trans);
 
        /* Allocate or reset and init all Tx and Command queues */
-       if (iwl_tx_init(trans))
+       if (iwl_pcie_tx_init(trans))
                return -ENOMEM;
 
        if (trans->cfg->base_params->shadow_reg_enable) {
@@ -871,7 +286,7 @@ static int iwl_nic_init(struct iwl_trans *trans)
 #define HW_READY_TIMEOUT (50)
 
 /* Note: returns poll_bit return value, which is >= 0 if success */
-static int iwl_set_hw_ready(struct iwl_trans *trans)
+static int iwl_pcie_set_hw_ready(struct iwl_trans *trans)
 {
        int ret;
 
@@ -889,14 +304,14 @@ static int iwl_set_hw_ready(struct iwl_trans *trans)
 }
 
 /* Note: returns standard 0/-ERROR code */
-static int iwl_prepare_card_hw(struct iwl_trans *trans)
+static int iwl_pcie_prepare_card_hw(struct iwl_trans *trans)
 {
        int ret;
        int t = 0;
 
        IWL_DEBUG_INFO(trans, "iwl_trans_prepare_card_hw enter\n");
 
-       ret = iwl_set_hw_ready(trans);
+       ret = iwl_pcie_set_hw_ready(trans);
        /* If the card is ready, exit 0 */
        if (ret >= 0)
                return 0;
@@ -906,7 +321,7 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
                    CSR_HW_IF_CONFIG_REG_PREPARE);
 
        do {
-               ret = iwl_set_hw_ready(trans);
+               ret = iwl_pcie_set_hw_ready(trans);
                if (ret >= 0)
                        return 0;
 
@@ -920,7 +335,7 @@ static int iwl_prepare_card_hw(struct iwl_trans *trans)
 /*
  * ucode
  */
-static int iwl_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr,
+static int iwl_pcie_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr,
                                   dma_addr_t phy_addr, u32 byte_cnt)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -967,7 +382,7 @@ static int iwl_load_firmware_chunk(struct iwl_trans *trans, u32 dst_addr,
        return 0;
 }
 
-static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
+static int iwl_pcie_load_section(struct iwl_trans *trans, u8 section_num,
                            const struct fw_desc *section)
 {
        u8 *v_addr;
@@ -988,8 +403,9 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
                copy_size = min_t(u32, PAGE_SIZE, section->len - offset);
 
                memcpy(v_addr, (u8 *)section->data + offset, copy_size);
-               ret = iwl_load_firmware_chunk(trans, section->offset + offset,
-                                             p_addr, copy_size);
+               ret = iwl_pcie_load_firmware_chunk(trans,
+                                                  section->offset + offset,
+                                                  p_addr, copy_size);
                if (ret) {
                        IWL_ERR(trans,
                                "Could not load the [%d] uCode section\n",
@@ -1002,7 +418,7 @@ static int iwl_load_section(struct iwl_trans *trans, u8 section_num,
        return ret;
 }
 
-static int iwl_load_given_ucode(struct iwl_trans *trans,
+static int iwl_pcie_load_given_ucode(struct iwl_trans *trans,
                                const struct fw_img *image)
 {
        int i, ret = 0;
@@ -1011,7 +427,7 @@ static int iwl_load_given_ucode(struct iwl_trans *trans,
                if (!image->sec[i].data)
                        break;
 
-               ret = iwl_load_section(trans, i, &image->sec[i]);
+               ret = iwl_pcie_load_section(trans, i, &image->sec[i]);
                if (ret)
                        return ret;
        }
@@ -1025,15 +441,18 @@ static int iwl_load_given_ucode(struct iwl_trans *trans,
 static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
                                   const struct fw_img *fw)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
        bool hw_rfkill;
 
        /* This may fail if AMT took ownership of the device */
-       if (iwl_prepare_card_hw(trans)) {
+       if (iwl_pcie_prepare_card_hw(trans)) {
                IWL_WARN(trans, "Exit HW not ready\n");
                return -EIO;
        }
 
+       clear_bit(STATUS_FW_ERROR, &trans_pcie->status);
+
        iwl_enable_rfkill_int(trans);
 
        /* If platform's RF_KILL switch is NOT set to KILL */
@@ -1044,7 +463,7 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
 
        iwl_write32(trans, CSR_INT, 0xFFFFFFFF);
 
-       ret = iwl_nic_init(trans);
+       ret = iwl_pcie_nic_init(trans);
        if (ret) {
                IWL_ERR(trans, "Unable to init nic\n");
                return ret;
@@ -1064,125 +483,13 @@ static int iwl_trans_pcie_start_fw(struct iwl_trans *trans,
        iwl_write32(trans, CSR_UCODE_DRV_GP1_CLR, CSR_UCODE_SW_BIT_RFKILL);
 
        /* Load the given image to the HW */
-       return iwl_load_given_ucode(trans, fw);
+       return iwl_pcie_load_given_ucode(trans, fw);
 }
 
-/*
- * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
- */
-static void iwl_trans_txq_set_sched(struct iwl_trans *trans, u32 mask)
+static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans, u32 scd_addr)
 {
-       struct iwl_trans_pcie __maybe_unused *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-
-       iwl_write_prph(trans, SCD_TXFACT, mask);
-}
-
-static void iwl_tx_start(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       u32 a;
-       int chan;
-       u32 reg_val;
-
-       /* make sure all queue are not stopped/used */
-       memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
-       memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
-
-       trans_pcie->scd_base_addr =
-               iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
-       a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
-       /* reset conext data memory */
-       for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
-               a += 4)
-               iwl_write_targ_mem(trans, a, 0);
-       /* reset tx status memory */
-       for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
-               a += 4)
-               iwl_write_targ_mem(trans, a, 0);
-       for (; a < trans_pcie->scd_base_addr +
-              SCD_TRANS_TBL_OFFSET_QUEUE(
-                               trans->cfg->base_params->num_of_queues);
-              a += 4)
-               iwl_write_targ_mem(trans, a, 0);
-
-       iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
-                      trans_pcie->scd_bc_tbls.dma >> 10);
-
-       /* The chain extension of the SCD doesn't work well. This feature is
-        * enabled by default by the HW, so we need to disable it manually.
-        */
-       iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
-
-       iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue,
-                               trans_pcie->cmd_fifo);
-
-       /* Activate all Tx DMA/FIFO channels */
-       iwl_trans_txq_set_sched(trans, IWL_MASK(0, 7));
-
-       /* Enable DMA channel */
-       for (chan = 0; chan < FH_TCSR_CHNL_NUM ; chan++)
-               iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
-                                  FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
-                                  FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
-
-       /* Update FH chicken bits */
-       reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG);
-       iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG,
-                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
-
-       /* Enable L1-Active */
-       iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
-                           APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
-}
-
-static void iwl_trans_pcie_fw_alive(struct iwl_trans *trans)
-{
-       iwl_reset_ict(trans);
-       iwl_tx_start(trans);
-}
-
-/**
- * iwlagn_txq_ctx_stop - Stop all Tx DMA channels
- */
-static int iwl_trans_tx_stop(struct iwl_trans *trans)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       int ch, txq_id, ret;
-       unsigned long flags;
-
-       /* Turn off all Tx DMA fifos */
-       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
-
-       iwl_trans_txq_set_sched(trans, 0);
-
-       /* Stop each Tx DMA channel, and wait for it to be idle */
-       for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
-               iwl_write_direct32(trans,
-                                  FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
-               ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
-                       FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000);
-               if (ret < 0)
-                       IWL_ERR(trans,
-                               "Failing on timeout while stopping DMA channel %d [0x%08x]\n",
-                               ch,
-                               iwl_read_direct32(trans,
-                                                 FH_TSSR_TX_STATUS_REG));
-       }
-       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
-
-       if (!trans_pcie->txq) {
-               IWL_WARN(trans,
-                        "Stopping tx queues that aren't allocated...\n");
-               return 0;
-       }
-
-       /* Unmap DMA from host system and free skb's */
-       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
-            txq_id++)
-               iwl_tx_queue_unmap(trans, txq_id);
-
-       return 0;
+       iwl_pcie_reset_ict(trans);
+       iwl_pcie_tx_start(trans, scd_addr);
 }
 
 static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
@@ -1196,7 +503,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
        /* device going down, Stop using ICT table */
-       iwl_disable_ict(trans);
+       iwl_pcie_disable_ict(trans);
 
        /*
         * If a HW restart happens during firmware loading,
@@ -1206,8 +513,8 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
         * already dead.
         */
        if (test_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status)) {
-               iwl_trans_tx_stop(trans);
-               iwl_trans_rx_stop(trans);
+               iwl_pcie_tx_stop(trans);
+               iwl_pcie_rx_stop(trans);
 
                /* Power-down device's busmaster DMA clocks */
                iwl_write_prph(trans, APMG_CLK_DIS_REG,
@@ -1220,7 +527,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
                      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 
        /* Stop the device, and put it in low power state */
-       iwl_apm_stop(trans);
+       iwl_pcie_apm_stop(trans);
 
        /* Upon stop, the APM issues an interrupt if HW RF kill is set.
         * Clean again the interrupt here
@@ -1245,6 +552,7 @@ static void iwl_trans_pcie_stop_device(struct iwl_trans *trans)
        clear_bit(STATUS_INT_ENABLED, &trans_pcie->status);
        clear_bit(STATUS_DEVICE_ENABLED, &trans_pcie->status);
        clear_bit(STATUS_TPOWER_PMI, &trans_pcie->status);
+       clear_bit(STATUS_RFKILL, &trans_pcie->status);
 }
 
 static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
@@ -1258,171 +566,6 @@ static void iwl_trans_pcie_wowlan_suspend(struct iwl_trans *trans)
                      CSR_GP_CNTRL_REG_FLAG_MAC_ACCESS_REQ);
 }
 
-static int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
-                            struct iwl_device_cmd *dev_cmd, int txq_id)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
-       struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *) dev_cmd->payload;
-       struct iwl_cmd_meta *out_meta;
-       struct iwl_tx_queue *txq;
-       struct iwl_queue *q;
-       dma_addr_t phys_addr = 0;
-       dma_addr_t txcmd_phys;
-       dma_addr_t scratch_phys;
-       u16 len, firstlen, secondlen;
-       u8 wait_write_ptr = 0;
-       __le16 fc = hdr->frame_control;
-       u8 hdr_len = ieee80211_hdrlen(fc);
-       u16 __maybe_unused wifi_seq;
-
-       txq = &trans_pcie->txq[txq_id];
-       q = &txq->q;
-
-       if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) {
-               WARN_ON_ONCE(1);
-               return -EINVAL;
-       }
-
-       spin_lock(&txq->lock);
-
-       /* In AGG mode, the index in the ring must correspond to the WiFi
-        * sequence number. This is a HW requirements to help the SCD to parse
-        * the BA.
-        * Check here that the packets are in the right place on the ring.
-        */
-#ifdef CONFIG_IWLWIFI_DEBUG
-       wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
-       WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) &&
-                 ((wifi_seq & 0xff) != q->write_ptr),
-                 "Q: %d WiFi Seq %d tfdNum %d",
-                 txq_id, wifi_seq, q->write_ptr);
-#endif
-
-       /* Set up driver data for this TFD */
-       txq->entries[q->write_ptr].skb = skb;
-       txq->entries[q->write_ptr].cmd = dev_cmd;
-
-       dev_cmd->hdr.cmd = REPLY_TX;
-       dev_cmd->hdr.sequence =
-               cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
-                           INDEX_TO_SEQ(q->write_ptr)));
-
-       /* Set up first empty entry in queue's array of Tx/cmd buffers */
-       out_meta = &txq->entries[q->write_ptr].meta;
-
-       /*
-        * Use the first empty entry in this queue's command buffer array
-        * to contain the Tx command and MAC header concatenated together
-        * (payload data will be in another buffer).
-        * Size of this varies, due to varying MAC header length.
-        * If end is not dword aligned, we'll have 2 extra bytes at the end
-        * of the MAC header (device reads on dword boundaries).
-        * We'll tell device about this padding later.
-        */
-       len = sizeof(struct iwl_tx_cmd) +
-               sizeof(struct iwl_cmd_header) + hdr_len;
-       firstlen = (len + 3) & ~3;
-
-       /* Tell NIC about any 2-byte padding after MAC header */
-       if (firstlen != len)
-               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
-
-       /* Physical address of this Tx command's header (not MAC header!),
-        * within command buffer array. */
-       txcmd_phys = dma_map_single(trans->dev,
-                                   &dev_cmd->hdr, firstlen,
-                                   DMA_BIDIRECTIONAL);
-       if (unlikely(dma_mapping_error(trans->dev, txcmd_phys)))
-               goto out_err;
-       dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
-       dma_unmap_len_set(out_meta, len, firstlen);
-
-       if (!ieee80211_has_morefrags(fc)) {
-               txq->need_update = 1;
-       } else {
-               wait_write_ptr = 1;
-               txq->need_update = 0;
-       }
-
-       /* Set up TFD's 2nd entry to point directly to remainder of skb,
-        * if any (802.11 null frames have no payload). */
-       secondlen = skb->len - hdr_len;
-       if (secondlen > 0) {
-               phys_addr = dma_map_single(trans->dev, skb->data + hdr_len,
-                                          secondlen, DMA_TO_DEVICE);
-               if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
-                       dma_unmap_single(trans->dev,
-                                        dma_unmap_addr(out_meta, mapping),
-                                        dma_unmap_len(out_meta, len),
-                                        DMA_BIDIRECTIONAL);
-                       goto out_err;
-               }
-       }
-
-       /* Attach buffers to TFD */
-       iwlagn_txq_attach_buf_to_tfd(trans, txq, txcmd_phys, firstlen, 1);
-       if (secondlen > 0)
-               iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
-                                            secondlen, 0);
-
-       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
-                               offsetof(struct iwl_tx_cmd, scratch);
-
-       /* take back ownership of DMA buffer to enable update */
-       dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen,
-                               DMA_BIDIRECTIONAL);
-       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
-       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
-
-       IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
-                    le16_to_cpu(dev_cmd->hdr.sequence));
-       IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
-
-       /* Set up entry for this TFD in Tx byte-count array */
-       iwl_trans_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
-
-       dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
-                                  DMA_BIDIRECTIONAL);
-
-       trace_iwlwifi_dev_tx(trans->dev, skb,
-                            &txq->tfds[txq->q.write_ptr],
-                            sizeof(struct iwl_tfd),
-                            &dev_cmd->hdr, firstlen,
-                            skb->data + hdr_len, secondlen);
-       trace_iwlwifi_dev_tx_data(trans->dev, skb,
-                                 skb->data + hdr_len, secondlen);
-
-       /* start timer if queue currently empty */
-       if (txq->need_update && q->read_ptr == q->write_ptr &&
-           trans_pcie->wd_timeout)
-               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
-
-       /* Tell device the write index *just past* this latest filled TFD */
-       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       iwl_txq_update_write_ptr(trans, txq);
-
-       /*
-        * At this point the frame is "transmitted" successfully
-        * and we will get a TX status notification eventually,
-        * regardless of the value of ret. "ret" only indicates
-        * whether or not we should update the write pointer.
-        */
-       if (iwl_queue_space(q) < q->high_mark) {
-               if (wait_write_ptr) {
-                       txq->need_update = 1;
-                       iwl_txq_update_write_ptr(trans, txq);
-               } else {
-                       iwl_stop_queue(trans, txq);
-               }
-       }
-       spin_unlock(&txq->lock);
-       return 0;
- out_err:
-       spin_unlock(&txq->lock);
-       return -1;
-}
-
 static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -1433,29 +576,28 @@ static int iwl_trans_pcie_start_hw(struct iwl_trans *trans)
 
        if (!trans_pcie->irq_requested) {
                tasklet_init(&trans_pcie->irq_tasklet, (void (*)(unsigned long))
-                       iwl_irq_tasklet, (unsigned long)trans);
+                       iwl_pcie_tasklet, (unsigned long)trans);
 
-               iwl_alloc_isr_ict(trans);
+               iwl_pcie_alloc_ict(trans);
 
-               err = request_irq(trans_pcie->irq, iwl_isr_ict, IRQF_SHARED,
-                                 DRV_NAME, trans);
+               err = request_irq(trans_pcie->irq, iwl_pcie_isr_ict,
+                                 IRQF_SHARED, DRV_NAME, trans);
                if (err) {
                        IWL_ERR(trans, "Error allocating IRQ %d\n",
                                trans_pcie->irq);
                        goto error;
                }
 
-               INIT_WORK(&trans_pcie->rx_replenish, iwl_bg_rx_replenish);
                trans_pcie->irq_requested = true;
        }
 
-       err = iwl_prepare_card_hw(trans);
+       err = iwl_pcie_prepare_card_hw(trans);
        if (err) {
                IWL_ERR(trans, "Error while preparing HW: %d\n", err);
                goto err_free_irq;
        }
 
-       iwl_apm_init(trans);
+       iwl_pcie_apm_init(trans);
 
        /* From now on, the op_mode will be kept updated about RF kill state */
        iwl_enable_rfkill_int(trans);
@@ -1469,7 +611,7 @@ err_free_irq:
        trans_pcie->irq_requested = false;
        free_irq(trans_pcie->irq, trans);
 error:
-       iwl_free_isr_ict(trans);
+       iwl_pcie_free_ict(trans);
        tasklet_kill(&trans_pcie->irq_tasklet);
        return err;
 }
@@ -1485,7 +627,7 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
        iwl_disable_interrupts(trans);
        spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
 
-       iwl_apm_stop(trans);
+       iwl_pcie_apm_stop(trans);
 
        spin_lock_irqsave(&trans_pcie->irq_lock, flags);
        iwl_disable_interrupts(trans);
@@ -1509,27 +651,6 @@ static void iwl_trans_pcie_stop_hw(struct iwl_trans *trans,
        }
 }
 
-static void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
-                                  struct sk_buff_head *skbs)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       /* n_bd is usually 256 => n_bd - 1 = 0xff */
-       int tfd_num = ssn & (txq->q.n_bd - 1);
-
-       spin_lock(&txq->lock);
-
-       if (txq->q.read_ptr != tfd_num) {
-               IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
-                                  txq_id, txq->q.read_ptr, tfd_num, ssn);
-               iwl_tx_queue_reclaim(trans, txq_id, tfd_num, skbs);
-               if (iwl_queue_space(&txq->q) > txq->q.low_mark)
-                       iwl_wake_queue(trans, txq);
-       }
-
-       spin_unlock(&txq->lock);
-}
-
 static void iwl_trans_pcie_write8(struct iwl_trans *trans, u32 ofs, u8 val)
 {
        writeb(val, IWL_TRANS_GET_PCIE_TRANS(trans)->hw_base + ofs);
@@ -1576,12 +697,12 @@ void iwl_trans_pcie_free(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
 
-       iwl_trans_pcie_tx_free(trans);
-       iwl_trans_pcie_rx_free(trans);
+       iwl_pcie_tx_free(trans);
+       iwl_pcie_rx_free(trans);
 
        if (trans_pcie->irq_requested == true) {
                free_irq(trans_pcie->irq, trans);
-               iwl_free_isr_ict(trans);
+               iwl_pcie_free_ict(trans);
        }
 
        pci_disable_msi(trans_pcie->pci_dev);
@@ -1627,10 +748,10 @@ static int iwl_trans_pcie_resume(struct iwl_trans *trans)
 
 #define IWL_FLUSH_WAIT_MS      2000
 
-static int iwl_trans_pcie_wait_tx_queue_empty(struct iwl_trans *trans)
+static int iwl_trans_pcie_wait_txq_empty(struct iwl_trans *trans)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq;
+       struct iwl_txq *txq;
        struct iwl_queue *q;
        int cnt;
        unsigned long now = jiffies;
@@ -1674,7 +795,7 @@ static const char *get_fh_string(int cmd)
 #undef IWL_CMD
 }
 
-int iwl_dump_fh(struct iwl_trans *trans, char **buf)
+int iwl_pcie_dump_fh(struct iwl_trans *trans, char **buf)
 {
        int i;
        static const u32 fh_tbl[] = {
@@ -1753,7 +874,7 @@ static const char *get_csr_string(int cmd)
 #undef IWL_CMD
 }
 
-void iwl_dump_csr(struct iwl_trans *trans)
+void iwl_pcie_dump_csr(struct iwl_trans *trans)
 {
        int i;
        static const u32 csr_tbl[] = {
@@ -1810,7 +931,6 @@ static ssize_t iwl_dbgfs_##name##_write(struct file *file,              \
                                        const char __user *user_buf,    \
                                        size_t count, loff_t *ppos);
 
-
 #define DEBUGFS_READ_FILE_OPS(name)                                    \
        DEBUGFS_READ_FUNC(name);                                        \
 static const struct file_operations iwl_dbgfs_##name##_ops = {         \
@@ -1843,7 +963,7 @@ static ssize_t iwl_dbgfs_tx_queue_read(struct file *file,
 {
        struct iwl_trans *trans = file->private_data;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq;
+       struct iwl_txq *txq;
        struct iwl_queue *q;
        char *buf;
        int pos = 0;
@@ -1880,7 +1000,7 @@ static ssize_t iwl_dbgfs_rx_queue_read(struct file *file,
 {
        struct iwl_trans *trans = file->private_data;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_rx_queue *rxq = &trans_pcie->rxq;
+       struct iwl_rxq *rxq = &trans_pcie->rxq;
        char buf[256];
        int pos = 0;
        const size_t bufsz = sizeof(buf);
@@ -1999,7 +1119,7 @@ static ssize_t iwl_dbgfs_csr_write(struct file *file,
        if (sscanf(buf, "%d", &csr) != 1)
                return -EFAULT;
 
-       iwl_dump_csr(trans);
+       iwl_pcie_dump_csr(trans);
 
        return count;
 }
@@ -2013,7 +1133,7 @@ static ssize_t iwl_dbgfs_fh_reg_read(struct file *file,
        int pos = 0;
        ssize_t ret = -EFAULT;
 
-       ret = pos = iwl_dump_fh(trans, &buf);
+       ret = pos = iwl_pcie_dump_fh(trans, &buf);
        if (buf) {
                ret = simple_read_from_buffer(user_buf,
                                              count, ppos, buf, pos);
@@ -2082,7 +1202,7 @@ static const struct iwl_trans_ops trans_ops_pcie = {
 
        .wowlan_suspend = iwl_trans_pcie_wowlan_suspend,
 
-       .send_cmd = iwl_trans_pcie_send_cmd,
+       .send_cmd = iwl_trans_pcie_send_hcmd,
 
        .tx = iwl_trans_pcie_tx,
        .reclaim = iwl_trans_pcie_reclaim,
@@ -2092,7 +1212,7 @@ static const struct iwl_trans_ops trans_ops_pcie = {
 
        .dbgfs_register = iwl_trans_pcie_dbgfs_register,
 
-       .wait_tx_queue_empty = iwl_trans_pcie_wait_tx_queue_empty,
+       .wait_tx_queue_empty = iwl_trans_pcie_wait_txq_empty,
 
 #ifdef CONFIG_PM_SLEEP
        .suspend = iwl_trans_pcie_suspend,
@@ -2117,7 +1237,7 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        trans = kzalloc(sizeof(struct iwl_trans) +
                        sizeof(struct iwl_trans_pcie), GFP_KERNEL);
 
-       if (WARN_ON(!trans))
+       if (!trans)
                return NULL;
 
        trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -2150,43 +1270,38 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
                                                          DMA_BIT_MASK(32));
                /* both attempts failed: */
                if (err) {
-                       dev_printk(KERN_ERR, &pdev->dev,
-                                  "No suitable DMA available.\n");
+                       dev_err(&pdev->dev, "No suitable DMA available\n");
                        goto out_pci_disable_device;
                }
        }
 
        err = pci_request_regions(pdev, DRV_NAME);
        if (err) {
-               dev_printk(KERN_ERR, &pdev->dev,
-                          "pci_request_regions failed\n");
+               dev_err(&pdev->dev, "pci_request_regions failed\n");
                goto out_pci_disable_device;
        }
 
        trans_pcie->hw_base = pci_ioremap_bar(pdev, 0);
        if (!trans_pcie->hw_base) {
-               dev_printk(KERN_ERR, &pdev->dev, "pci_ioremap_bar failed\n");
+               dev_err(&pdev->dev, "pci_ioremap_bar failed\n");
                err = -ENODEV;
                goto out_pci_release_regions;
        }
 
-       dev_printk(KERN_INFO, &pdev->dev,
-                  "pci_resource_len = 0x%08llx\n",
-                  (unsigned long long) pci_resource_len(pdev, 0));
-       dev_printk(KERN_INFO, &pdev->dev,
-                  "pci_resource_base = %p\n", trans_pcie->hw_base);
-
-       dev_printk(KERN_INFO, &pdev->dev,
-                  "HW Revision ID = 0x%X\n", pdev->revision);
-
        /* We disable the RETRY_TIMEOUT register (0x41) to keep
         * PCI Tx retries from interfering with C3 CPU state */
        pci_write_config_byte(pdev, PCI_CFG_RETRY_TIMEOUT, 0x00);
 
        err = pci_enable_msi(pdev);
-       if (err)
-               dev_printk(KERN_ERR, &pdev->dev,
-                          "pci_enable_msi failed(0X%x)\n", err);
+       if (err) {
+               dev_err(&pdev->dev, "pci_enable_msi failed(0X%x)\n", err);
+               /* enable rfkill interrupt: hw bug w/a */
+               pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
+               if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
+                       pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
+                       pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
+               }
+       }
 
        trans->dev = &pdev->dev;
        trans_pcie->irq = pdev->irq;
@@ -2196,16 +1311,8 @@ struct iwl_trans *iwl_trans_pcie_alloc(struct pci_dev *pdev,
        snprintf(trans->hw_id_str, sizeof(trans->hw_id_str),
                 "PCI ID: 0x%04X:0x%04X", pdev->device, pdev->subsystem_device);
 
-       /* TODO: Move this away, not needed if not MSI */
-       /* enable rfkill interrupt: hw bug w/a */
-       pci_read_config_word(pdev, PCI_COMMAND, &pci_cmd);
-       if (pci_cmd & PCI_COMMAND_INTX_DISABLE) {
-               pci_cmd &= ~PCI_COMMAND_INTX_DISABLE;
-               pci_write_config_word(pdev, PCI_COMMAND, pci_cmd);
-       }
-
        /* Initialize the wait queue for commands */
-       init_waitqueue_head(&trans->wait_command_queue);
+       init_waitqueue_head(&trans_pcie->wait_command_queue);
        spin_lock_init(&trans->reg_lock);
 
        snprintf(trans->dev_cmd_pool_name, sizeof(trans->dev_cmd_pool_name),
index db3efbb84d9221d96c933062758504fb74f5f283..6c5b867c353ae83cd79404bece14d83989cba6a8 100644 (file)
 #define IWL_TX_CRC_SIZE 4
 #define IWL_TX_DELIMITER_SIZE 4
 
-/**
- * iwl_trans_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
+/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
+ * DMA services
+ *
+ * Theory of operation
+ *
+ * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
+ * of buffer descriptors, each of which points to one or more data buffers for
+ * the device to read from or fill.  Driver and device exchange status of each
+ * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
+ * entries in each circular buffer, to protect against confusing empty and full
+ * queue states.
+ *
+ * The device reads or writes the data in the queues via the device's several
+ * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
+ *
+ * For Tx queue, there are low mark and high mark limits. If, after queuing
+ * the packet for Tx, free space become < low mark, Tx queue stopped. When
+ * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
+ * Tx queue resumed.
+ *
+ ***************************************************/
+static int iwl_queue_space(const struct iwl_queue *q)
+{
+       int s = q->read_ptr - q->write_ptr;
+
+       if (q->read_ptr > q->write_ptr)
+               s -= q->n_bd;
+
+       if (s <= 0)
+               s += q->n_window;
+       /* keep some reserve to not confuse empty and full situations */
+       s -= 2;
+       if (s < 0)
+               s = 0;
+       return s;
+}
+
+/*
+ * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
+ */
+static int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id)
+{
+       q->n_bd = count;
+       q->n_window = slots_num;
+       q->id = id;
+
+       /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
+        * and iwl_queue_dec_wrap are broken. */
+       if (WARN_ON(!is_power_of_2(count)))
+               return -EINVAL;
+
+       /* slots_num must be power-of-two size, otherwise
+        * get_cmd_index is broken. */
+       if (WARN_ON(!is_power_of_2(slots_num)))
+               return -EINVAL;
+
+       q->low_mark = q->n_window / 4;
+       if (q->low_mark < 4)
+               q->low_mark = 4;
+
+       q->high_mark = q->n_window / 8;
+       if (q->high_mark < 2)
+               q->high_mark = 2;
+
+       q->write_ptr = 0;
+       q->read_ptr = 0;
+
+       return 0;
+}
+
+static int iwl_pcie_alloc_dma_ptr(struct iwl_trans *trans,
+                                 struct iwl_dma_ptr *ptr, size_t size)
+{
+       if (WARN_ON(ptr->addr))
+               return -EINVAL;
+
+       ptr->addr = dma_alloc_coherent(trans->dev, size,
+                                      &ptr->dma, GFP_KERNEL);
+       if (!ptr->addr)
+               return -ENOMEM;
+       ptr->size = size;
+       return 0;
+}
+
+static void iwl_pcie_free_dma_ptr(struct iwl_trans *trans,
+                                 struct iwl_dma_ptr *ptr)
+{
+       if (unlikely(!ptr->addr))
+               return;
+
+       dma_free_coherent(trans->dev, ptr->size, ptr->addr, ptr->dma);
+       memset(ptr, 0, sizeof(*ptr));
+}
+
+static void iwl_pcie_txq_stuck_timer(unsigned long data)
+{
+       struct iwl_txq *txq = (void *)data;
+       struct iwl_queue *q = &txq->q;
+       struct iwl_trans_pcie *trans_pcie = txq->trans_pcie;
+       struct iwl_trans *trans = iwl_trans_pcie_get_trans(trans_pcie);
+       u32 scd_sram_addr = trans_pcie->scd_base_addr +
+                               SCD_TX_STTS_QUEUE_OFFSET(txq->q.id);
+       u8 buf[16];
+       int i;
+
+       spin_lock(&txq->lock);
+       /* check if triggered erroneously */
+       if (txq->q.read_ptr == txq->q.write_ptr) {
+               spin_unlock(&txq->lock);
+               return;
+       }
+       spin_unlock(&txq->lock);
+
+       IWL_ERR(trans, "Queue %d stuck for %u ms.\n", txq->q.id,
+               jiffies_to_msecs(trans_pcie->wd_timeout));
+       IWL_ERR(trans, "Current SW read_ptr %d write_ptr %d\n",
+               txq->q.read_ptr, txq->q.write_ptr);
+
+       iwl_read_targ_mem_bytes(trans, scd_sram_addr, buf, sizeof(buf));
+
+       iwl_print_hex_error(trans, buf, sizeof(buf));
+
+       for (i = 0; i < FH_TCSR_CHNL_NUM; i++)
+               IWL_ERR(trans, "FH TRBs(%d) = 0x%08x\n", i,
+                       iwl_read_direct32(trans, FH_TX_TRB_REG(i)));
+
+       for (i = 0; i < trans->cfg->base_params->num_of_queues; i++) {
+               u32 status = iwl_read_prph(trans, SCD_QUEUE_STATUS_BITS(i));
+               u8 fifo = (status >> SCD_QUEUE_STTS_REG_POS_TXF) & 0x7;
+               bool active = !!(status & BIT(SCD_QUEUE_STTS_REG_POS_ACTIVE));
+               u32 tbl_dw =
+                       iwl_read_targ_mem(trans,
+                                         trans_pcie->scd_base_addr +
+                                         SCD_TRANS_TBL_OFFSET_QUEUE(i));
+
+               if (i & 0x1)
+                       tbl_dw = (tbl_dw & 0xFFFF0000) >> 16;
+               else
+                       tbl_dw = tbl_dw & 0x0000FFFF;
+
+               IWL_ERR(trans,
+                       "Q %d is %sactive and mapped to fifo %d ra_tid 0x%04x [%d,%d]\n",
+                       i, active ? "" : "in", fifo, tbl_dw,
+                       iwl_read_prph(trans,
+                                     SCD_QUEUE_RDPTR(i)) & (txq->q.n_bd - 1),
+                       iwl_read_prph(trans, SCD_QUEUE_WRPTR(i)));
+       }
+
+       for (i = q->read_ptr; i != q->write_ptr;
+            i = iwl_queue_inc_wrap(i, q->n_bd)) {
+               struct iwl_tx_cmd *tx_cmd =
+                       (struct iwl_tx_cmd *)txq->entries[i].cmd->payload;
+               IWL_ERR(trans, "scratch %d = 0x%08x\n", i,
+                       get_unaligned_le32(&tx_cmd->scratch));
+       }
+
+       iwl_op_mode_nic_error(trans->op_mode);
+}
+
+/*
+ * iwl_pcie_txq_update_byte_cnt_tbl - Set up entry in Tx byte-count array
  */
-void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
-                                      struct iwl_tx_queue *txq,
-                                      u16 byte_cnt)
+static void iwl_pcie_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
+                                            struct iwl_txq *txq, u16 byte_cnt)
 {
        struct iwlagn_scd_bc_tbl *scd_bc_tbl;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -88,10 +246,36 @@ void iwl_trans_txq_update_byte_cnt_tbl(struct iwl_trans *trans,
                        tfd_offset[TFD_QUEUE_SIZE_MAX + write_ptr] = bc_ent;
 }
 
-/**
- * iwl_txq_update_write_ptr - Send new write index to hardware
+static void iwl_pcie_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
+                                           struct iwl_txq *txq)
+{
+       struct iwl_trans_pcie *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
+       int txq_id = txq->q.id;
+       int read_ptr = txq->q.read_ptr;
+       u8 sta_id = 0;
+       __le16 bc_ent;
+       struct iwl_tx_cmd *tx_cmd =
+               (void *)txq->entries[txq->q.read_ptr].cmd->payload;
+
+       WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
+
+       if (txq_id != trans_pcie->cmd_queue)
+               sta_id = tx_cmd->sta_id;
+
+       bc_ent = cpu_to_le16(1 | (sta_id << 12));
+       scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
+
+       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
+               scd_bc_tbl[txq_id].
+                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
+}
+
+/*
+ * iwl_pcie_txq_inc_wr_ptr - Send new write index to hardware
  */
-void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq)
+void iwl_pcie_txq_inc_wr_ptr(struct iwl_trans *trans, struct iwl_txq *txq)
 {
        u32 reg = 0;
        int txq_id = txq->q.id;
@@ -137,7 +321,7 @@ void iwl_txq_update_write_ptr(struct iwl_trans *trans, struct iwl_tx_queue *txq)
        txq->need_update = 0;
 }
 
-static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
+static inline dma_addr_t iwl_pcie_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
 {
        struct iwl_tfd_tb *tb = &tfd->tbs[idx];
 
@@ -149,15 +333,15 @@ static inline dma_addr_t iwl_tfd_tb_get_addr(struct iwl_tfd *tfd, u8 idx)
        return addr;
 }
 
-static inline u16 iwl_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
+static inline u16 iwl_pcie_tfd_tb_get_len(struct iwl_tfd *tfd, u8 idx)
 {
        struct iwl_tfd_tb *tb = &tfd->tbs[idx];
 
        return le16_to_cpu(tb->hi_n_len) >> 4;
 }
 
-static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
-                                 dma_addr_t addr, u16 len)
+static inline void iwl_pcie_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
+                                      dma_addr_t addr, u16 len)
 {
        struct iwl_tfd_tb *tb = &tfd->tbs[idx];
        u16 hi_n_len = len << 4;
@@ -171,19 +355,20 @@ static inline void iwl_tfd_set_tb(struct iwl_tfd *tfd, u8 idx,
        tfd->num_tbs = idx + 1;
 }
 
-static inline u8 iwl_tfd_get_num_tbs(struct iwl_tfd *tfd)
+static inline u8 iwl_pcie_tfd_get_num_tbs(struct iwl_tfd *tfd)
 {
        return tfd->num_tbs & 0x1f;
 }
 
-static void iwl_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
-                         struct iwl_tfd *tfd, enum dma_data_direction dma_dir)
+static void iwl_pcie_tfd_unmap(struct iwl_trans *trans,
+                              struct iwl_cmd_meta *meta, struct iwl_tfd *tfd,
+                              enum dma_data_direction dma_dir)
 {
        int i;
        int num_tbs;
 
        /* Sanity check on number of chunks */
-       num_tbs = iwl_tfd_get_num_tbs(tfd);
+       num_tbs = iwl_pcie_tfd_get_num_tbs(tfd);
 
        if (num_tbs >= IWL_NUM_OF_TBS) {
                IWL_ERR(trans, "Too many chunks: %i\n", num_tbs);
@@ -200,14 +385,14 @@ static void iwl_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
 
        /* Unmap chunks, if any. */
        for (i = 1; i < num_tbs; i++)
-               dma_unmap_single(trans->dev, iwl_tfd_tb_get_addr(tfd, i),
-                               iwl_tfd_tb_get_len(tfd, i), dma_dir);
+               dma_unmap_single(trans->dev, iwl_pcie_tfd_tb_get_addr(tfd, i),
+                                iwl_pcie_tfd_tb_get_len(tfd, i), dma_dir);
 
        tfd->num_tbs = 0;
 }
 
-/**
- * iwl_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
+/*
+ * iwl_pcie_txq_free_tfd - Free all chunks referenced by TFD [txq->q.read_ptr]
  * @trans - transport private data
  * @txq - tx queue
  * @dma_dir - the direction of the DMA mapping
@@ -215,8 +400,8 @@ static void iwl_unmap_tfd(struct iwl_trans *trans, struct iwl_cmd_meta *meta,
  * Does NOT advance any TFD circular buffer read/write indexes
  * Does NOT free the TFD itself (which is within circular buffer)
  */
-void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
-                     enum dma_data_direction dma_dir)
+static void iwl_pcie_txq_free_tfd(struct iwl_trans *trans, struct iwl_txq *txq,
+                                 enum dma_data_direction dma_dir)
 {
        struct iwl_tfd *tfd_tmp = txq->tfds;
 
@@ -227,8 +412,8 @@ void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
        lockdep_assert_held(&txq->lock);
 
        /* We have only q->n_window txq->entries, but we use q->n_bd tfds */
-       iwl_unmap_tfd(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr],
-                     dma_dir);
+       iwl_pcie_tfd_unmap(trans, &txq->entries[idx].meta, &tfd_tmp[rd_ptr],
+                          dma_dir);
 
        /* free SKB */
        if (txq->entries) {
@@ -247,10 +432,8 @@ void iwl_txq_free_tfd(struct iwl_trans *trans, struct iwl_tx_queue *txq,
        }
 }
 
-int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
-                                struct iwl_tx_queue *txq,
-                                dma_addr_t addr, u16 len,
-                                u8 reset)
+static int iwl_pcie_txq_build_tfd(struct iwl_trans *trans, struct iwl_txq *txq,
+                                 dma_addr_t addr, u16 len, u8 reset)
 {
        struct iwl_queue *q;
        struct iwl_tfd *tfd, *tfd_tmp;
@@ -263,124 +446,550 @@ int iwlagn_txq_attach_buf_to_tfd(struct iwl_trans *trans,
        if (reset)
                memset(tfd, 0, sizeof(*tfd));
 
-       num_tbs = iwl_tfd_get_num_tbs(tfd);
+       num_tbs = iwl_pcie_tfd_get_num_tbs(tfd);
+
+       /* Each TFD can point to a maximum 20 Tx buffers */
+       if (num_tbs >= IWL_NUM_OF_TBS) {
+               IWL_ERR(trans, "Error can not send more than %d chunks\n",
+                       IWL_NUM_OF_TBS);
+               return -EINVAL;
+       }
+
+       if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
+               return -EINVAL;
+
+       if (unlikely(addr & ~IWL_TX_DMA_MASK))
+               IWL_ERR(trans, "Unaligned address = %llx\n",
+                       (unsigned long long)addr);
+
+       iwl_pcie_tfd_set_tb(tfd, num_tbs, addr, len);
+
+       return 0;
+}
+
+static int iwl_pcie_txq_alloc(struct iwl_trans *trans,
+                              struct iwl_txq *txq, int slots_num,
+                              u32 txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       size_t tfd_sz = sizeof(struct iwl_tfd) * TFD_QUEUE_SIZE_MAX;
+       int i;
+
+       if (WARN_ON(txq->entries || txq->tfds))
+               return -EINVAL;
+
+       setup_timer(&txq->stuck_timer, iwl_pcie_txq_stuck_timer,
+                   (unsigned long)txq);
+       txq->trans_pcie = trans_pcie;
+
+       txq->q.n_window = slots_num;
+
+       txq->entries = kcalloc(slots_num,
+                              sizeof(struct iwl_pcie_txq_entry),
+                              GFP_KERNEL);
+
+       if (!txq->entries)
+               goto error;
+
+       if (txq_id == trans_pcie->cmd_queue)
+               for (i = 0; i < slots_num; i++) {
+                       txq->entries[i].cmd =
+                               kmalloc(sizeof(struct iwl_device_cmd),
+                                       GFP_KERNEL);
+                       if (!txq->entries[i].cmd)
+                               goto error;
+               }
+
+       /* Circular buffer of transmit frame descriptors (TFDs),
+        * shared with device */
+       txq->tfds = dma_alloc_coherent(trans->dev, tfd_sz,
+                                      &txq->q.dma_addr, GFP_KERNEL);
+       if (!txq->tfds) {
+               IWL_ERR(trans, "dma_alloc_coherent(%zd) failed\n", tfd_sz);
+               goto error;
+       }
+       txq->q.id = txq_id;
+
+       return 0;
+error:
+       if (txq->entries && txq_id == trans_pcie->cmd_queue)
+               for (i = 0; i < slots_num; i++)
+                       kfree(txq->entries[i].cmd);
+       kfree(txq->entries);
+       txq->entries = NULL;
+
+       return -ENOMEM;
+
+}
+
+static int iwl_pcie_txq_init(struct iwl_trans *trans, struct iwl_txq *txq,
+                             int slots_num, u32 txq_id)
+{
+       int ret;
+
+       txq->need_update = 0;
+
+       /* TFD_QUEUE_SIZE_MAX must be power-of-two size, otherwise
+        * iwl_queue_inc_wrap and iwl_queue_dec_wrap are broken. */
+       BUILD_BUG_ON(TFD_QUEUE_SIZE_MAX & (TFD_QUEUE_SIZE_MAX - 1));
+
+       /* Initialize queue's high/low-water marks, and head/tail indexes */
+       ret = iwl_queue_init(&txq->q, TFD_QUEUE_SIZE_MAX, slots_num,
+                       txq_id);
+       if (ret)
+               return ret;
+
+       spin_lock_init(&txq->lock);
+
+       /*
+        * Tell nic where to find circular buffer of Tx Frame Descriptors for
+        * given Tx queue, and enable the DMA channel used for that queue.
+        * Circular buffer (TFD queue in DRAM) physical base address */
+       iwl_write_direct32(trans, FH_MEM_CBBC_QUEUE(txq_id),
+                          txq->q.dma_addr >> 8);
+
+       return 0;
+}
+
+/*
+ * iwl_pcie_txq_unmap -  Unmap any remaining DMA mappings and free skb's
+ */
+static void iwl_pcie_txq_unmap(struct iwl_trans *trans, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_txq *txq = &trans_pcie->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       enum dma_data_direction dma_dir;
+
+       if (!q->n_bd)
+               return;
+
+       /* In the command queue, all the TBs are mapped as BIDI
+        * so unmap them as such.
+        */
+       if (txq_id == trans_pcie->cmd_queue)
+               dma_dir = DMA_BIDIRECTIONAL;
+       else
+               dma_dir = DMA_TO_DEVICE;
+
+       spin_lock_bh(&txq->lock);
+       while (q->write_ptr != q->read_ptr) {
+               iwl_pcie_txq_free_tfd(trans, txq, dma_dir);
+               q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd);
+       }
+       spin_unlock_bh(&txq->lock);
+}
+
+/*
+ * iwl_pcie_txq_free - Deallocate DMA queue.
+ * @txq: Transmit queue to deallocate.
+ *
+ * Empty queue by removing and destroying all BD's.
+ * Free all buffers.
+ * 0-fill, but do not free "txq" descriptor structure.
+ */
+static void iwl_pcie_txq_free(struct iwl_trans *trans, int txq_id)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_txq *txq = &trans_pcie->txq[txq_id];
+       struct device *dev = trans->dev;
+       int i;
+
+       if (WARN_ON(!txq))
+               return;
+
+       iwl_pcie_txq_unmap(trans, txq_id);
+
+       /* De-alloc array of command/tx buffers */
+       if (txq_id == trans_pcie->cmd_queue)
+               for (i = 0; i < txq->q.n_window; i++) {
+                       kfree(txq->entries[i].cmd);
+                       kfree(txq->entries[i].copy_cmd);
+                       kfree(txq->entries[i].free_buf);
+               }
+
+       /* De-alloc circular buffer of TFDs */
+       if (txq->q.n_bd) {
+               dma_free_coherent(dev, sizeof(struct iwl_tfd) *
+                                 txq->q.n_bd, txq->tfds, txq->q.dma_addr);
+               memset(&txq->q.dma_addr, 0, sizeof(txq->q.dma_addr));
+       }
+
+       kfree(txq->entries);
+       txq->entries = NULL;
+
+       del_timer_sync(&txq->stuck_timer);
+
+       /* 0-fill queue descriptor structure */
+       memset(txq, 0, sizeof(*txq));
+}
+
+/*
+ * Activate/Deactivate Tx DMA/FIFO channels according tx fifos mask
+ */
+static void iwl_pcie_txq_set_sched(struct iwl_trans *trans, u32 mask)
+{
+       struct iwl_trans_pcie __maybe_unused *trans_pcie =
+               IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       iwl_write_prph(trans, SCD_TXFACT, mask);
+}
+
+void iwl_pcie_tx_start(struct iwl_trans *trans, u32 scd_base_addr)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       u32 a;
+       int chan;
+       u32 reg_val;
+
+       /* make sure all queue are not stopped/used */
+       memset(trans_pcie->queue_stopped, 0, sizeof(trans_pcie->queue_stopped));
+       memset(trans_pcie->queue_used, 0, sizeof(trans_pcie->queue_used));
+
+       trans_pcie->scd_base_addr =
+               iwl_read_prph(trans, SCD_SRAM_BASE_ADDR);
+
+       WARN_ON(scd_base_addr != 0 &&
+               scd_base_addr != trans_pcie->scd_base_addr);
+
+       a = trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_LOWER_BOUND;
+       /* reset conext data memory */
+       for (; a < trans_pcie->scd_base_addr + SCD_CONTEXT_MEM_UPPER_BOUND;
+               a += 4)
+               iwl_write_targ_mem(trans, a, 0);
+       /* reset tx status memory */
+       for (; a < trans_pcie->scd_base_addr + SCD_TX_STTS_MEM_UPPER_BOUND;
+               a += 4)
+               iwl_write_targ_mem(trans, a, 0);
+       for (; a < trans_pcie->scd_base_addr +
+              SCD_TRANS_TBL_OFFSET_QUEUE(
+                               trans->cfg->base_params->num_of_queues);
+              a += 4)
+               iwl_write_targ_mem(trans, a, 0);
+
+       iwl_write_prph(trans, SCD_DRAM_BASE_ADDR,
+                      trans_pcie->scd_bc_tbls.dma >> 10);
+
+       /* The chain extension of the SCD doesn't work well. This feature is
+        * enabled by default by the HW, so we need to disable it manually.
+        */
+       iwl_write_prph(trans, SCD_CHAINEXT_EN, 0);
+
+       iwl_trans_ac_txq_enable(trans, trans_pcie->cmd_queue,
+                               trans_pcie->cmd_fifo);
+
+       /* Activate all Tx DMA/FIFO channels */
+       iwl_pcie_txq_set_sched(trans, IWL_MASK(0, 7));
+
+       /* Enable DMA channel */
+       for (chan = 0; chan < FH_TCSR_CHNL_NUM; chan++)
+               iwl_write_direct32(trans, FH_TCSR_CHNL_TX_CONFIG_REG(chan),
+                                  FH_TCSR_TX_CONFIG_REG_VAL_DMA_CHNL_ENABLE |
+                                  FH_TCSR_TX_CONFIG_REG_VAL_DMA_CREDIT_ENABLE);
+
+       /* Update FH chicken bits */
+       reg_val = iwl_read_direct32(trans, FH_TX_CHICKEN_BITS_REG);
+       iwl_write_direct32(trans, FH_TX_CHICKEN_BITS_REG,
+                          reg_val | FH_TX_CHICKEN_BITS_SCD_AUTO_RETRY_EN);
+
+       /* Enable L1-Active */
+       iwl_clear_bits_prph(trans, APMG_PCIDEV_STT_REG,
+                           APMG_PCIDEV_STT_VAL_L1_ACT_DIS);
+}
+
+/*
+ * iwl_pcie_tx_stop - Stop all Tx DMA channels
+ */
+int iwl_pcie_tx_stop(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ch, txq_id, ret;
+       unsigned long flags;
+
+       /* Turn off all Tx DMA fifos */
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+       iwl_pcie_txq_set_sched(trans, 0);
+
+       /* Stop each Tx DMA channel, and wait for it to be idle */
+       for (ch = 0; ch < FH_TCSR_CHNL_NUM; ch++) {
+               iwl_write_direct32(trans,
+                                  FH_TCSR_CHNL_TX_CONFIG_REG(ch), 0x0);
+               ret = iwl_poll_direct_bit(trans, FH_TSSR_TX_STATUS_REG,
+                       FH_TSSR_TX_STATUS_REG_MSK_CHNL_IDLE(ch), 1000);
+               if (ret < 0)
+                       IWL_ERR(trans,
+                               "Failing on timeout while stopping DMA channel %d [0x%08x]\n",
+                               ch,
+                               iwl_read_direct32(trans,
+                                                 FH_TSSR_TX_STATUS_REG));
+       }
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       if (!trans_pcie->txq) {
+               IWL_WARN(trans,
+                        "Stopping tx queues that aren't allocated...\n");
+               return 0;
+       }
+
+       /* Unmap DMA from host system and free skb's */
+       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+            txq_id++)
+               iwl_pcie_txq_unmap(trans, txq_id);
+
+       return 0;
+}
+
+/*
+ * iwl_trans_tx_free - Free TXQ Context
+ *
+ * Destroy all TX DMA queues and structures
+ */
+void iwl_pcie_tx_free(struct iwl_trans *trans)
+{
+       int txq_id;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       /* Tx queues */
+       if (trans_pcie->txq) {
+               for (txq_id = 0;
+                    txq_id < trans->cfg->base_params->num_of_queues; txq_id++)
+                       iwl_pcie_txq_free(trans, txq_id);
+       }
+
+       kfree(trans_pcie->txq);
+       trans_pcie->txq = NULL;
+
+       iwl_pcie_free_dma_ptr(trans, &trans_pcie->kw);
+
+       iwl_pcie_free_dma_ptr(trans, &trans_pcie->scd_bc_tbls);
+}
+
+/*
+ * iwl_pcie_tx_alloc - allocate TX context
+ * Allocate all Tx DMA structures and initialize them
+ */
+static int iwl_pcie_tx_alloc(struct iwl_trans *trans)
+{
+       int ret;
+       int txq_id, slots_num;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       u16 scd_bc_tbls_size = trans->cfg->base_params->num_of_queues *
+                       sizeof(struct iwlagn_scd_bc_tbl);
+
+       /*It is not allowed to alloc twice, so warn when this happens.
+        * We cannot rely on the previous allocation, so free and fail */
+       if (WARN_ON(trans_pcie->txq)) {
+               ret = -EINVAL;
+               goto error;
+       }
+
+       ret = iwl_pcie_alloc_dma_ptr(trans, &trans_pcie->scd_bc_tbls,
+                                  scd_bc_tbls_size);
+       if (ret) {
+               IWL_ERR(trans, "Scheduler BC Table allocation failed\n");
+               goto error;
+       }
+
+       /* Alloc keep-warm buffer */
+       ret = iwl_pcie_alloc_dma_ptr(trans, &trans_pcie->kw, IWL_KW_SIZE);
+       if (ret) {
+               IWL_ERR(trans, "Keep Warm allocation failed\n");
+               goto error;
+       }
+
+       trans_pcie->txq = kcalloc(trans->cfg->base_params->num_of_queues,
+                                 sizeof(struct iwl_txq), GFP_KERNEL);
+       if (!trans_pcie->txq) {
+               IWL_ERR(trans, "Not enough memory for txq\n");
+               ret = ENOMEM;
+               goto error;
+       }
+
+       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
+       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+            txq_id++) {
+               slots_num = (txq_id == trans_pcie->cmd_queue) ?
+                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               ret = iwl_pcie_txq_alloc(trans, &trans_pcie->txq[txq_id],
+                                         slots_num, txq_id);
+               if (ret) {
+                       IWL_ERR(trans, "Tx %d queue alloc failed\n", txq_id);
+                       goto error;
+               }
+       }
+
+       return 0;
+
+error:
+       iwl_pcie_tx_free(trans);
+
+       return ret;
+}
+int iwl_pcie_tx_init(struct iwl_trans *trans)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       int ret;
+       int txq_id, slots_num;
+       unsigned long flags;
+       bool alloc = false;
+
+       if (!trans_pcie->txq) {
+               ret = iwl_pcie_tx_alloc(trans);
+               if (ret)
+                       goto error;
+               alloc = true;
+       }
+
+       spin_lock_irqsave(&trans_pcie->irq_lock, flags);
+
+       /* Turn off all Tx DMA fifos */
+       iwl_write_prph(trans, SCD_TXFACT, 0);
+
+       /* Tell NIC where to find the "keep warm" buffer */
+       iwl_write_direct32(trans, FH_KW_MEM_ADDR_REG,
+                          trans_pcie->kw.dma >> 4);
+
+       spin_unlock_irqrestore(&trans_pcie->irq_lock, flags);
+
+       /* Alloc and init all Tx queues, including the command queue (#4/#9) */
+       for (txq_id = 0; txq_id < trans->cfg->base_params->num_of_queues;
+            txq_id++) {
+               slots_num = (txq_id == trans_pcie->cmd_queue) ?
+                                       TFD_CMD_SLOTS : TFD_TX_CMD_SLOTS;
+               ret = iwl_pcie_txq_init(trans, &trans_pcie->txq[txq_id],
+                                        slots_num, txq_id);
+               if (ret) {
+                       IWL_ERR(trans, "Tx %d queue init failed\n", txq_id);
+                       goto error;
+               }
+       }
+
+       return 0;
+error:
+       /*Upon error, free only if we allocated something */
+       if (alloc)
+               iwl_pcie_tx_free(trans);
+       return ret;
+}
+
+static inline void iwl_pcie_txq_progress(struct iwl_trans_pcie *trans_pcie,
+                                          struct iwl_txq *txq)
+{
+       if (!trans_pcie->wd_timeout)
+               return;
+
+       /*
+        * if empty delete timer, otherwise move timer forward
+        * since we're making progress on this queue
+        */
+       if (txq->q.read_ptr == txq->q.write_ptr)
+               del_timer(&txq->stuck_timer);
+       else
+               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+}
 
-       /* Each TFD can point to a maximum 20 Tx buffers */
-       if (num_tbs >= IWL_NUM_OF_TBS) {
-               IWL_ERR(trans, "Error can not send more than %d chunks\n",
-                       IWL_NUM_OF_TBS);
-               return -EINVAL;
-       }
+/* Frees buffers until index _not_ inclusive */
+void iwl_trans_pcie_reclaim(struct iwl_trans *trans, int txq_id, int ssn,
+                           struct sk_buff_head *skbs)
+{
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_txq *txq = &trans_pcie->txq[txq_id];
+       /* n_bd is usually 256 => n_bd - 1 = 0xff */
+       int tfd_num = ssn & (txq->q.n_bd - 1);
+       struct iwl_queue *q = &txq->q;
+       int last_to_free;
 
-       if (WARN_ON(addr & ~DMA_BIT_MASK(36)))
-               return -EINVAL;
+       /* This function is not meant to release cmd queue*/
+       if (WARN_ON(txq_id == trans_pcie->cmd_queue))
+               return;
 
-       if (unlikely(addr & ~IWL_TX_DMA_MASK))
-               IWL_ERR(trans, "Unaligned address = %llx\n",
-                       (unsigned long long)addr);
+       spin_lock(&txq->lock);
 
-       iwl_tfd_set_tb(tfd, num_tbs, addr, len);
+       if (txq->q.read_ptr == tfd_num)
+               goto out;
 
-       return 0;
-}
+       IWL_DEBUG_TX_REPLY(trans, "[Q %d] %d -> %d (%d)\n",
+                          txq_id, txq->q.read_ptr, tfd_num, ssn);
 
-/*************** DMA-QUEUE-GENERAL-FUNCTIONS  *****
- * DMA services
- *
- * Theory of operation
- *
- * A Tx or Rx queue resides in host DRAM, and is comprised of a circular buffer
- * of buffer descriptors, each of which points to one or more data buffers for
- * the device to read from or fill.  Driver and device exchange status of each
- * queue via "read" and "write" pointers.  Driver keeps minimum of 2 empty
- * entries in each circular buffer, to protect against confusing empty and full
- * queue states.
- *
- * The device reads or writes the data in the queues via the device's several
- * DMA/FIFO channels.  Each queue is mapped to a single DMA channel.
- *
- * For Tx queue, there are low mark and high mark limits. If, after queuing
- * the packet for Tx, free space become < low mark, Tx queue stopped. When
- * reclaiming packets (on 'tx done IRQ), if free space become > high mark,
- * Tx queue resumed.
- *
- ***************************************************/
+       /*Since we free until index _not_ inclusive, the one before index is
+        * the last we will free. This one must be used */
+       last_to_free = iwl_queue_dec_wrap(tfd_num, q->n_bd);
 
-int iwl_queue_space(const struct iwl_queue *q)
-{
-       int s = q->read_ptr - q->write_ptr;
+       if (!iwl_queue_used(q, last_to_free)) {
+               IWL_ERR(trans,
+                       "%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n",
+                       __func__, txq_id, last_to_free, q->n_bd,
+                       q->write_ptr, q->read_ptr);
+               goto out;
+       }
 
-       if (q->read_ptr > q->write_ptr)
-               s -= q->n_bd;
+       if (WARN_ON(!skb_queue_empty(skbs)))
+               goto out;
 
-       if (s <= 0)
-               s += q->n_window;
-       /* keep some reserve to not confuse empty and full situations */
-       s -= 2;
-       if (s < 0)
-               s = 0;
-       return s;
-}
+       for (;
+            q->read_ptr != tfd_num;
+            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
-/**
- * iwl_queue_init - Initialize queue's high/low-water and read/write indexes
- */
-int iwl_queue_init(struct iwl_queue *q, int count, int slots_num, u32 id)
-{
-       q->n_bd = count;
-       q->n_window = slots_num;
-       q->id = id;
+               if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL))
+                       continue;
 
-       /* count must be power-of-two size, otherwise iwl_queue_inc_wrap
-        * and iwl_queue_dec_wrap are broken. */
-       if (WARN_ON(!is_power_of_2(count)))
-               return -EINVAL;
+               __skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb);
 
-       /* slots_num must be power-of-two size, otherwise
-        * get_cmd_index is broken. */
-       if (WARN_ON(!is_power_of_2(slots_num)))
-               return -EINVAL;
+               txq->entries[txq->q.read_ptr].skb = NULL;
 
-       q->low_mark = q->n_window / 4;
-       if (q->low_mark < 4)
-               q->low_mark = 4;
+               iwl_pcie_txq_inval_byte_cnt_tbl(trans, txq);
 
-       q->high_mark = q->n_window / 8;
-       if (q->high_mark < 2)
-               q->high_mark = 2;
+               iwl_pcie_txq_free_tfd(trans, txq, DMA_TO_DEVICE);
+       }
 
-       q->write_ptr = q->read_ptr = 0;
+       iwl_pcie_txq_progress(trans_pcie, txq);
 
-       return 0;
+       if (iwl_queue_space(&txq->q) > txq->q.low_mark)
+               iwl_wake_queue(trans, txq);
+out:
+       spin_unlock(&txq->lock);
 }
 
-static void iwlagn_txq_inval_byte_cnt_tbl(struct iwl_trans *trans,
-                                         struct iwl_tx_queue *txq)
+/*
+ * iwl_pcie_cmdq_reclaim - Reclaim TX command queue entries already Tx'd
+ *
+ * When FW advances 'R' index, all entries between old and new 'R' index
+ * need to be reclaimed. As result, some free space forms.  If there is
+ * enough free space (> low mark), wake the stack that feeds us.
+ */
+static void iwl_pcie_cmdq_reclaim(struct iwl_trans *trans, int txq_id, int idx)
 {
-       struct iwl_trans_pcie *trans_pcie =
-               IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwlagn_scd_bc_tbl *scd_bc_tbl = trans_pcie->scd_bc_tbls.addr;
-       int txq_id = txq->q.id;
-       int read_ptr = txq->q.read_ptr;
-       u8 sta_id = 0;
-       __le16 bc_ent;
-       struct iwl_tx_cmd *tx_cmd =
-               (void *)txq->entries[txq->q.read_ptr].cmd->payload;
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+       struct iwl_txq *txq = &trans_pcie->txq[txq_id];
+       struct iwl_queue *q = &txq->q;
+       int nfreed = 0;
 
-       WARN_ON(read_ptr >= TFD_QUEUE_SIZE_MAX);
+       lockdep_assert_held(&txq->lock);
 
-       if (txq_id != trans_pcie->cmd_queue)
-               sta_id = tx_cmd->sta_id;
+       if ((idx >= q->n_bd) || (!iwl_queue_used(q, idx))) {
+               IWL_ERR(trans,
+                       "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n",
+                       __func__, txq_id, idx, q->n_bd,
+                       q->write_ptr, q->read_ptr);
+               return;
+       }
 
-       bc_ent = cpu_to_le16(1 | (sta_id << 12));
-       scd_bc_tbl[txq_id].tfd_offset[read_ptr] = bc_ent;
+       for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
+            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
 
-       if (read_ptr < TFD_QUEUE_SIZE_BC_DUP)
-               scd_bc_tbl[txq_id].
-                       tfd_offset[TFD_QUEUE_SIZE_MAX + read_ptr] = bc_ent;
+               if (nfreed++ > 0) {
+                       IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
+                               idx, q->write_ptr, q->read_ptr);
+                       iwl_op_mode_nic_error(trans->op_mode);
+               }
+       }
+
+       iwl_pcie_txq_progress(trans_pcie, txq);
 }
 
-static int iwl_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
+static int iwl_pcie_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
                                 u16 txq_id)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
@@ -405,7 +1014,8 @@ static int iwl_txq_set_ratid_map(struct iwl_trans *trans, u16 ra_tid,
        return 0;
 }
 
-static inline void iwl_txq_set_inactive(struct iwl_trans *trans, u16 txq_id)
+static inline void iwl_pcie_txq_set_inactive(struct iwl_trans *trans,
+                                            u16 txq_id)
 {
        /* Simply stop the queue, but don't change any configuration;
         * the SCD_ACT_EN bit is the write-enable mask for the ACTIVE bit. */
@@ -424,7 +1034,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
                WARN_ONCE(1, "queue %d already used - expect issues", txq_id);
 
        /* Stop this Tx queue before configuring it */
-       iwl_txq_set_inactive(trans, txq_id);
+       iwl_pcie_txq_set_inactive(trans, txq_id);
 
        /* Set this queue as a chain-building queue unless it is CMD queue */
        if (txq_id != trans_pcie->cmd_queue)
@@ -435,7 +1045,7 @@ void iwl_trans_pcie_txq_enable(struct iwl_trans *trans, int txq_id, int fifo,
                u16 ra_tid = BUILD_RAxTID(sta_id, tid);
 
                /* Map receiver-address / traffic-ID to this queue */
-               iwl_txq_set_ratid_map(trans, ra_tid, txq_id);
+               iwl_pcie_txq_set_ratid_map(trans, ra_tid, txq_id);
 
                /* enable aggregations for the queue */
                iwl_set_bits_prph(trans, SCD_AGGR_SEL, BIT(txq_id));
@@ -489,18 +1099,20 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
                return;
        }
 
-       iwl_txq_set_inactive(trans, txq_id);
+       iwl_pcie_txq_set_inactive(trans, txq_id);
 
        _iwl_write_targ_mem_dwords(trans, stts_addr,
                                   zero_val, ARRAY_SIZE(zero_val));
 
+       iwl_pcie_txq_unmap(trans, txq_id);
+
        IWL_DEBUG_TX_QUEUES(trans, "Deactivate queue %d\n", txq_id);
 }
 
 /*************** HOST COMMAND QUEUE FUNCTIONS   *****/
 
-/**
- * iwl_enqueue_hcmd - enqueue a uCode command
+/*
+ * iwl_pcie_enqueue_hcmd - enqueue a uCode command
  * @priv: device private data point
  * @cmd: a point to the ucode command structure
  *
@@ -508,15 +1120,17 @@ void iwl_trans_pcie_txq_disable(struct iwl_trans *trans, int txq_id)
  * failed. On success, it turns the index (> 0) of command in the
  * command queue.
  */
-static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+static int iwl_pcie_enqueue_hcmd(struct iwl_trans *trans,
+                                struct iwl_host_cmd *cmd)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+       struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
        struct iwl_queue *q = &txq->q;
        struct iwl_device_cmd *out_cmd;
        struct iwl_cmd_meta *out_meta;
+       void *dup_buf = NULL;
        dma_addr_t phys_addr;
-       u32 idx;
+       int idx;
        u16 copy_size, cmd_size;
        bool had_nocopy = false;
        int i;
@@ -533,10 +1147,33 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                        continue;
                if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY) {
                        had_nocopy = true;
+                       if (WARN_ON(cmd->dataflags[i] & IWL_HCMD_DFL_DUP)) {
+                               idx = -EINVAL;
+                               goto free_dup_buf;
+                       }
+               } else if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP) {
+                       /*
+                        * This is also a chunk that isn't copied
+                        * to the static buffer so set had_nocopy.
+                        */
+                       had_nocopy = true;
+
+                       /* only allowed once */
+                       if (WARN_ON(dup_buf)) {
+                               idx = -EINVAL;
+                               goto free_dup_buf;
+                       }
+
+                       dup_buf = kmemdup(cmd->data[i], cmd->len[i],
+                                         GFP_ATOMIC);
+                       if (!dup_buf)
+                               return -ENOMEM;
                } else {
                        /* NOCOPY must not be followed by normal! */
-                       if (WARN_ON(had_nocopy))
-                               return -EINVAL;
+                       if (WARN_ON(had_nocopy)) {
+                               idx = -EINVAL;
+                               goto free_dup_buf;
+                       }
                        copy_size += cmd->len[i];
                }
                cmd_size += cmd->len[i];
@@ -550,9 +1187,10 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
         */
        if (WARN(copy_size > TFD_MAX_PAYLOAD_SIZE,
                 "Command %s (%#x) is too large (%d bytes)\n",
-                trans_pcie_get_cmd_string(trans_pcie, cmd->id),
-                cmd->id, copy_size))
-               return -EINVAL;
+                get_cmd_string(trans_pcie, cmd->id), cmd->id, copy_size)) {
+               idx = -EINVAL;
+               goto free_dup_buf;
+       }
 
        spin_lock_bh(&txq->lock);
 
@@ -561,7 +1199,8 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
                IWL_ERR(trans, "No space in command queue\n");
                iwl_op_mode_cmd_queue_full(trans->op_mode);
-               return -ENOSPC;
+               idx = -ENOSPC;
+               goto free_dup_buf;
        }
 
        idx = get_cmd_index(q, q->write_ptr);
@@ -585,7 +1224,8 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
                if (!cmd->len[i])
                        continue;
-               if (cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY)
+               if (cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |
+                                        IWL_HCMD_DFL_DUP))
                        break;
                memcpy((u8 *)out_cmd + cmd_pos, cmd->data[i], cmd->len[i]);
                cmd_pos += cmd->len[i];
@@ -610,7 +1250,7 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
        IWL_DEBUG_HC(trans,
                     "Sending command %s (#%x), seq: 0x%04X, %d bytes at %d[%d]:%d\n",
-                    trans_pcie_get_cmd_string(trans_pcie, out_cmd->hdr.cmd),
+                    get_cmd_string(trans_pcie, out_cmd->hdr.cmd),
                     out_cmd->hdr.cmd, le16_to_cpu(out_cmd->hdr.sequence),
                     cmd_size, q->write_ptr, idx, trans_pcie->cmd_queue);
 
@@ -624,28 +1264,35 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        dma_unmap_addr_set(out_meta, mapping, phys_addr);
        dma_unmap_len_set(out_meta, len, copy_size);
 
-       iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr, copy_size, 1);
+       iwl_pcie_txq_build_tfd(trans, txq, phys_addr, copy_size, 1);
 
        for (i = 0; i < IWL_MAX_CMD_TFDS; i++) {
+               const void *data = cmd->data[i];
+
                if (!cmd->len[i])
                        continue;
-               if (!(cmd->dataflags[i] & IWL_HCMD_DFL_NOCOPY))
+               if (!(cmd->dataflags[i] & (IWL_HCMD_DFL_NOCOPY |
+                                          IWL_HCMD_DFL_DUP)))
                        continue;
-               phys_addr = dma_map_single(trans->dev, (void *)cmd->data[i],
+               if (cmd->dataflags[i] & IWL_HCMD_DFL_DUP)
+                       data = dup_buf;
+               phys_addr = dma_map_single(trans->dev, (void *)data,
                                           cmd->len[i], DMA_BIDIRECTIONAL);
                if (dma_mapping_error(trans->dev, phys_addr)) {
-                       iwl_unmap_tfd(trans, out_meta,
-                                     &txq->tfds[q->write_ptr],
-                                     DMA_BIDIRECTIONAL);
+                       iwl_pcie_tfd_unmap(trans, out_meta,
+                                          &txq->tfds[q->write_ptr],
+                                          DMA_BIDIRECTIONAL);
                        idx = -ENOMEM;
                        goto out;
                }
 
-               iwlagn_txq_attach_buf_to_tfd(trans, txq, phys_addr,
-                                            cmd->len[i], 0);
+               iwl_pcie_txq_build_tfd(trans, txq, phys_addr, cmd->len[i], 0);
        }
 
        out_meta->flags = cmd->flags;
+       if (WARN_ON_ONCE(txq->entries[idx].free_buf))
+               kfree(txq->entries[idx].free_buf);
+       txq->entries[idx].free_buf = dup_buf;
 
        txq->need_update = 1;
 
@@ -658,70 +1305,18 @@ static int iwl_enqueue_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 
        /* Increment and update queue's write index */
        q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
-       iwl_txq_update_write_ptr(trans, txq);
+       iwl_pcie_txq_inc_wr_ptr(trans, txq);
 
  out:
        spin_unlock_bh(&txq->lock);
+ free_dup_buf:
+       if (idx < 0)
+               kfree(dup_buf);
        return idx;
 }
 
-static inline void iwl_queue_progress(struct iwl_trans_pcie *trans_pcie,
-                                     struct iwl_tx_queue *txq)
-{
-       if (!trans_pcie->wd_timeout)
-               return;
-
-       /*
-        * if empty delete timer, otherwise move timer forward
-        * since we're making progress on this queue
-        */
-       if (txq->q.read_ptr == txq->q.write_ptr)
-               del_timer(&txq->stuck_timer);
-       else
-               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
-}
-
-/**
- * iwl_hcmd_queue_reclaim - Reclaim TX command queue entries already Tx'd
- *
- * When FW advances 'R' index, all entries between old and new 'R' index
- * need to be reclaimed. As result, some free space forms.  If there is
- * enough free space (> low mark), wake the stack that feeds us.
- */
-static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
-                                  int idx)
-{
-       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-       int nfreed = 0;
-
-       lockdep_assert_held(&txq->lock);
-
-       if ((idx >= q->n_bd) || (iwl_queue_used(q, idx) == 0)) {
-               IWL_ERR(trans,
-                       "%s: Read index for DMA queue txq id (%d), index %d is out of range [0-%d] %d %d.\n",
-                       __func__, txq_id, idx, q->n_bd,
-                       q->write_ptr, q->read_ptr);
-               return;
-       }
-
-       for (idx = iwl_queue_inc_wrap(idx, q->n_bd); q->read_ptr != idx;
-            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
-
-               if (nfreed++ > 0) {
-                       IWL_ERR(trans, "HCMD skipped: index (%d) %d %d\n",
-                               idx, q->write_ptr, q->read_ptr);
-                       iwl_op_mode_nic_error(trans->op_mode);
-               }
-
-       }
-
-       iwl_queue_progress(trans_pcie, txq);
-}
-
-/**
- * iwl_tx_cmd_complete - Pull unused buffers off the queue and reclaim them
+/*
+ * iwl_pcie_hcmd_complete - Pull unused buffers off the queue and reclaim them
  * @rxb: Rx buffer to reclaim
  * @handler_status: return value of the handler of the command
  *     (put in setup_rx_handlers)
@@ -730,8 +1325,8 @@ static void iwl_hcmd_queue_reclaim(struct iwl_trans *trans, int txq_id,
  * will be executed.  The attached skb (if present) will only be freed
  * if the callback returns 1
  */
-void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
-                        int handler_status)
+void iwl_pcie_hcmd_complete(struct iwl_trans *trans,
+                           struct iwl_rx_cmd_buffer *rxb, int handler_status)
 {
        struct iwl_rx_packet *pkt = rxb_addr(rxb);
        u16 sequence = le16_to_cpu(pkt->hdr.sequence);
@@ -741,7 +1336,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
        struct iwl_device_cmd *cmd;
        struct iwl_cmd_meta *meta;
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
+       struct iwl_txq *txq = &trans_pcie->txq[trans_pcie->cmd_queue];
 
        /* If a Tx command is being handled and it isn't in the actual
         * command queue then there a command routing bug has been introduced
@@ -761,7 +1356,7 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
        cmd = txq->entries[cmd_index].cmd;
        meta = &txq->entries[cmd_index].meta;
 
-       iwl_unmap_tfd(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL);
+       iwl_pcie_tfd_unmap(trans, meta, &txq->tfds[index], DMA_BIDIRECTIONAL);
 
        /* Input error checking is done when commands are added to queue. */
        if (meta->flags & CMD_WANT_SKB) {
@@ -773,20 +1368,18 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
                meta->source->handler_status = handler_status;
        }
 
-       iwl_hcmd_queue_reclaim(trans, txq_id, index);
+       iwl_pcie_cmdq_reclaim(trans, txq_id, index);
 
        if (!(meta->flags & CMD_ASYNC)) {
                if (!test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
                        IWL_WARN(trans,
                                 "HCMD_ACTIVE already clear for command %s\n",
-                                trans_pcie_get_cmd_string(trans_pcie,
-                                                          cmd->hdr.cmd));
+                                get_cmd_string(trans_pcie, cmd->hdr.cmd));
                }
                clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
                IWL_DEBUG_INFO(trans, "Clearing HCMD_ACTIVE for command %s\n",
-                              trans_pcie_get_cmd_string(trans_pcie,
-                                                        cmd->hdr.cmd));
-               wake_up(&trans->wait_command_queue);
+                              get_cmd_string(trans_pcie, cmd->hdr.cmd));
+               wake_up(&trans_pcie->wait_command_queue);
        }
 
        meta->flags = 0;
@@ -796,7 +1389,8 @@ void iwl_tx_cmd_complete(struct iwl_trans *trans, struct iwl_rx_cmd_buffer *rxb,
 
 #define HOST_COMPLETE_TIMEOUT (2 * HZ)
 
-static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+static int iwl_pcie_send_hcmd_async(struct iwl_trans *trans,
+                                   struct iwl_host_cmd *cmd)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int ret;
@@ -805,59 +1399,59 @@ static int iwl_send_cmd_async(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
        if (WARN_ON(cmd->flags & CMD_WANT_SKB))
                return -EINVAL;
 
-
-       ret = iwl_enqueue_hcmd(trans, cmd);
+       ret = iwl_pcie_enqueue_hcmd(trans, cmd);
        if (ret < 0) {
                IWL_ERR(trans,
                        "Error sending %s: enqueue_hcmd failed: %d\n",
-                       trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
+                       get_cmd_string(trans_pcie, cmd->id), ret);
                return ret;
        }
        return 0;
 }
 
-static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+static int iwl_pcie_send_hcmd_sync(struct iwl_trans *trans,
+                                  struct iwl_host_cmd *cmd)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
        int cmd_idx;
        int ret;
 
        IWL_DEBUG_INFO(trans, "Attempting to send sync command %s\n",
-                      trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+                      get_cmd_string(trans_pcie, cmd->id));
 
        if (WARN_ON(test_and_set_bit(STATUS_HCMD_ACTIVE,
                                     &trans_pcie->status))) {
                IWL_ERR(trans, "Command %s: a command is already active!\n",
-                       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+                       get_cmd_string(trans_pcie, cmd->id));
                return -EIO;
        }
 
        IWL_DEBUG_INFO(trans, "Setting HCMD_ACTIVE for command %s\n",
-                      trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+                      get_cmd_string(trans_pcie, cmd->id));
 
-       cmd_idx = iwl_enqueue_hcmd(trans, cmd);
+       cmd_idx = iwl_pcie_enqueue_hcmd(trans, cmd);
        if (cmd_idx < 0) {
                ret = cmd_idx;
                clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
                IWL_ERR(trans,
                        "Error sending %s: enqueue_hcmd failed: %d\n",
-                       trans_pcie_get_cmd_string(trans_pcie, cmd->id), ret);
+                       get_cmd_string(trans_pcie, cmd->id), ret);
                return ret;
        }
 
-       ret = wait_event_timeout(trans->wait_command_queue,
+       ret = wait_event_timeout(trans_pcie->wait_command_queue,
                                 !test_bit(STATUS_HCMD_ACTIVE,
                                           &trans_pcie->status),
                                 HOST_COMPLETE_TIMEOUT);
        if (!ret) {
                if (test_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status)) {
-                       struct iwl_tx_queue *txq =
+                       struct iwl_txq *txq =
                                &trans_pcie->txq[trans_pcie->cmd_queue];
                        struct iwl_queue *q = &txq->q;
 
                        IWL_ERR(trans,
                                "Error sending %s: time out after %dms.\n",
-                               trans_pcie_get_cmd_string(trans_pcie, cmd->id),
+                               get_cmd_string(trans_pcie, cmd->id),
                                jiffies_to_msecs(HOST_COMPLETE_TIMEOUT));
 
                        IWL_ERR(trans,
@@ -867,16 +1461,28 @@ static int iwl_send_cmd_sync(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
                        clear_bit(STATUS_HCMD_ACTIVE, &trans_pcie->status);
                        IWL_DEBUG_INFO(trans,
                                       "Clearing HCMD_ACTIVE for command %s\n",
-                                      trans_pcie_get_cmd_string(trans_pcie,
-                                                                cmd->id));
+                                      get_cmd_string(trans_pcie, cmd->id));
                        ret = -ETIMEDOUT;
                        goto cancel;
                }
        }
 
+       if (test_bit(STATUS_FW_ERROR, &trans_pcie->status)) {
+               IWL_ERR(trans, "FW error in SYNC CMD %s\n",
+                       get_cmd_string(trans_pcie, cmd->id));
+               ret = -EIO;
+               goto cancel;
+       }
+
+       if (test_bit(STATUS_RFKILL, &trans_pcie->status)) {
+               IWL_DEBUG_RF_KILL(trans, "RFKILL in SYNC CMD... no rsp\n");
+               ret = -ERFKILL;
+               goto cancel;
+       }
+
        if ((cmd->flags & CMD_WANT_SKB) && !cmd->resp_pkt) {
                IWL_ERR(trans, "Error: Response NULL in '%s'\n",
-                       trans_pcie_get_cmd_string(trans_pcie, cmd->id));
+                       get_cmd_string(trans_pcie, cmd->id));
                ret = -EIO;
                goto cancel;
        }
@@ -903,64 +1509,183 @@ cancel:
        return ret;
 }
 
-int iwl_trans_pcie_send_cmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
+int iwl_trans_pcie_send_hcmd(struct iwl_trans *trans, struct iwl_host_cmd *cmd)
 {
+       struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
+
+       if (test_bit(STATUS_FW_ERROR, &trans_pcie->status))
+               return -EIO;
+
+       if (test_bit(STATUS_RFKILL, &trans_pcie->status))
+               return -ERFKILL;
+
        if (cmd->flags & CMD_ASYNC)
-               return iwl_send_cmd_async(trans, cmd);
+               return iwl_pcie_send_hcmd_async(trans, cmd);
 
-       return iwl_send_cmd_sync(trans, cmd);
+       /* We still can fail on RFKILL that can be asserted while we wait */
+       return iwl_pcie_send_hcmd_sync(trans, cmd);
 }
 
-/* Frees buffers until index _not_ inclusive */
-int iwl_tx_queue_reclaim(struct iwl_trans *trans, int txq_id, int index,
-                        struct sk_buff_head *skbs)
+int iwl_trans_pcie_tx(struct iwl_trans *trans, struct sk_buff *skb,
+                     struct iwl_device_cmd *dev_cmd, int txq_id)
 {
        struct iwl_trans_pcie *trans_pcie = IWL_TRANS_GET_PCIE_TRANS(trans);
-       struct iwl_tx_queue *txq = &trans_pcie->txq[txq_id];
-       struct iwl_queue *q = &txq->q;
-       int last_to_free;
-       int freed = 0;
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct iwl_tx_cmd *tx_cmd = (struct iwl_tx_cmd *)dev_cmd->payload;
+       struct iwl_cmd_meta *out_meta;
+       struct iwl_txq *txq;
+       struct iwl_queue *q;
+       dma_addr_t phys_addr = 0;
+       dma_addr_t txcmd_phys;
+       dma_addr_t scratch_phys;
+       u16 len, firstlen, secondlen;
+       u8 wait_write_ptr = 0;
+       __le16 fc = hdr->frame_control;
+       u8 hdr_len = ieee80211_hdrlen(fc);
+       u16 __maybe_unused wifi_seq;
+
+       txq = &trans_pcie->txq[txq_id];
+       q = &txq->q;
 
-       /* This function is not meant to release cmd queue*/
-       if (WARN_ON(txq_id == trans_pcie->cmd_queue))
-               return 0;
+       if (unlikely(!test_bit(txq_id, trans_pcie->queue_used))) {
+               WARN_ON_ONCE(1);
+               return -EINVAL;
+       }
 
-       lockdep_assert_held(&txq->lock);
+       spin_lock(&txq->lock);
 
-       /*Since we free until index _not_ inclusive, the one before index is
-        * the last we will free. This one must be used */
-       last_to_free = iwl_queue_dec_wrap(index, q->n_bd);
+       /* In AGG mode, the index in the ring must correspond to the WiFi
+        * sequence number. This is a HW requirements to help the SCD to parse
+        * the BA.
+        * Check here that the packets are in the right place on the ring.
+        */
+#ifdef CONFIG_IWLWIFI_DEBUG
+       wifi_seq = SEQ_TO_SN(le16_to_cpu(hdr->seq_ctrl));
+       WARN_ONCE((iwl_read_prph(trans, SCD_AGGR_SEL) & BIT(txq_id)) &&
+                 ((wifi_seq & 0xff) != q->write_ptr),
+                 "Q: %d WiFi Seq %d tfdNum %d",
+                 txq_id, wifi_seq, q->write_ptr);
+#endif
+
+       /* Set up driver data for this TFD */
+       txq->entries[q->write_ptr].skb = skb;
+       txq->entries[q->write_ptr].cmd = dev_cmd;
+
+       dev_cmd->hdr.cmd = REPLY_TX;
+       dev_cmd->hdr.sequence =
+               cpu_to_le16((u16)(QUEUE_TO_SEQ(txq_id) |
+                           INDEX_TO_SEQ(q->write_ptr)));
+
+       /* Set up first empty entry in queue's array of Tx/cmd buffers */
+       out_meta = &txq->entries[q->write_ptr].meta;
 
-       if ((index >= q->n_bd) ||
-          (iwl_queue_used(q, last_to_free) == 0)) {
-               IWL_ERR(trans,
-                       "%s: Read index for DMA queue txq id (%d), last_to_free %d is out of range [0-%d] %d %d.\n",
-                       __func__, txq_id, last_to_free, q->n_bd,
-                       q->write_ptr, q->read_ptr);
-               return 0;
+       /*
+        * Use the first empty entry in this queue's command buffer array
+        * to contain the Tx command and MAC header concatenated together
+        * (payload data will be in another buffer).
+        * Size of this varies, due to varying MAC header length.
+        * If end is not dword aligned, we'll have 2 extra bytes at the end
+        * of the MAC header (device reads on dword boundaries).
+        * We'll tell device about this padding later.
+        */
+       len = sizeof(struct iwl_tx_cmd) +
+               sizeof(struct iwl_cmd_header) + hdr_len;
+       firstlen = (len + 3) & ~3;
+
+       /* Tell NIC about any 2-byte padding after MAC header */
+       if (firstlen != len)
+               tx_cmd->tx_flags |= TX_CMD_FLG_MH_PAD_MSK;
+
+       /* Physical address of this Tx command's header (not MAC header!),
+        * within command buffer array. */
+       txcmd_phys = dma_map_single(trans->dev,
+                                   &dev_cmd->hdr, firstlen,
+                                   DMA_BIDIRECTIONAL);
+       if (unlikely(dma_mapping_error(trans->dev, txcmd_phys)))
+               goto out_err;
+       dma_unmap_addr_set(out_meta, mapping, txcmd_phys);
+       dma_unmap_len_set(out_meta, len, firstlen);
+
+       if (!ieee80211_has_morefrags(fc)) {
+               txq->need_update = 1;
+       } else {
+               wait_write_ptr = 1;
+               txq->need_update = 0;
        }
 
-       if (WARN_ON(!skb_queue_empty(skbs)))
-               return 0;
+       /* Set up TFD's 2nd entry to point directly to remainder of skb,
+        * if any (802.11 null frames have no payload). */
+       secondlen = skb->len - hdr_len;
+       if (secondlen > 0) {
+               phys_addr = dma_map_single(trans->dev, skb->data + hdr_len,
+                                          secondlen, DMA_TO_DEVICE);
+               if (unlikely(dma_mapping_error(trans->dev, phys_addr))) {
+                       dma_unmap_single(trans->dev,
+                                        dma_unmap_addr(out_meta, mapping),
+                                        dma_unmap_len(out_meta, len),
+                                        DMA_BIDIRECTIONAL);
+                       goto out_err;
+               }
+       }
 
-       for (;
-            q->read_ptr != index;
-            q->read_ptr = iwl_queue_inc_wrap(q->read_ptr, q->n_bd)) {
+       /* Attach buffers to TFD */
+       iwl_pcie_txq_build_tfd(trans, txq, txcmd_phys, firstlen, 1);
+       if (secondlen > 0)
+               iwl_pcie_txq_build_tfd(trans, txq, phys_addr, secondlen, 0);
 
-               if (WARN_ON_ONCE(txq->entries[txq->q.read_ptr].skb == NULL))
-                       continue;
+       scratch_phys = txcmd_phys + sizeof(struct iwl_cmd_header) +
+                               offsetof(struct iwl_tx_cmd, scratch);
 
-               __skb_queue_tail(skbs, txq->entries[txq->q.read_ptr].skb);
+       /* take back ownership of DMA buffer to enable update */
+       dma_sync_single_for_cpu(trans->dev, txcmd_phys, firstlen,
+                               DMA_BIDIRECTIONAL);
+       tx_cmd->dram_lsb_ptr = cpu_to_le32(scratch_phys);
+       tx_cmd->dram_msb_ptr = iwl_get_dma_hi_addr(scratch_phys);
 
-               txq->entries[txq->q.read_ptr].skb = NULL;
+       IWL_DEBUG_TX(trans, "sequence nr = 0X%x\n",
+                    le16_to_cpu(dev_cmd->hdr.sequence));
+       IWL_DEBUG_TX(trans, "tx_flags = 0X%x\n", le32_to_cpu(tx_cmd->tx_flags));
 
-               iwlagn_txq_inval_byte_cnt_tbl(trans, txq);
+       /* Set up entry for this TFD in Tx byte-count array */
+       iwl_pcie_txq_update_byte_cnt_tbl(trans, txq, le16_to_cpu(tx_cmd->len));
 
-               iwl_txq_free_tfd(trans, txq, DMA_TO_DEVICE);
-               freed++;
-       }
+       dma_sync_single_for_device(trans->dev, txcmd_phys, firstlen,
+                                  DMA_BIDIRECTIONAL);
+
+       trace_iwlwifi_dev_tx(trans->dev, skb,
+                            &txq->tfds[txq->q.write_ptr],
+                            sizeof(struct iwl_tfd),
+                            &dev_cmd->hdr, firstlen,
+                            skb->data + hdr_len, secondlen);
+       trace_iwlwifi_dev_tx_data(trans->dev, skb,
+                                 skb->data + hdr_len, secondlen);
 
-       iwl_queue_progress(trans_pcie, txq);
+       /* start timer if queue currently empty */
+       if (txq->need_update && q->read_ptr == q->write_ptr &&
+           trans_pcie->wd_timeout)
+               mod_timer(&txq->stuck_timer, jiffies + trans_pcie->wd_timeout);
+
+       /* Tell device the write index *just past* this latest filled TFD */
+       q->write_ptr = iwl_queue_inc_wrap(q->write_ptr, q->n_bd);
+       iwl_pcie_txq_inc_wr_ptr(trans, txq);
 
-       return freed;
+       /*
+        * At this point the frame is "transmitted" successfully
+        * and we will get a TX status notification eventually,
+        * regardless of the value of ret. "ret" only indicates
+        * whether or not we should update the write pointer.
+        */
+       if (iwl_queue_space(q) < q->high_mark) {
+               if (wait_write_ptr) {
+                       txq->need_update = 1;
+                       iwl_pcie_txq_inc_wr_ptr(trans, txq);
+               } else {
+                       iwl_stop_queue(trans, txq);
+               }
+       }
+       spin_unlock(&txq->lock);
+       return 0;
+out_err:
+       spin_unlock(&txq->lock);
+       return -1;
 }
index 1c10b542ab231a45e5134a58ceb858c8ab82d331..ec36868f6fc50a50c2edcc8d8fee9e72153890f3 100644 (file)
@@ -436,19 +436,19 @@ static int lbs_add_wpa_tlv(u8 *tlv, const u8 *ie, u8 ie_len)
  */
 
 static int lbs_cfg_set_monitor_channel(struct wiphy *wiphy,
-                                      struct ieee80211_channel *channel,
-                                      enum nl80211_channel_type channel_type)
+                                      struct cfg80211_chan_def *chandef)
 {
        struct lbs_private *priv = wiphy_priv(wiphy);
        int ret = -ENOTSUPP;
 
        lbs_deb_enter_args(LBS_DEB_CFG80211, "freq %d, type %d",
-                          channel->center_freq, channel_type);
+                          chandef->chan->center_freq,
+                          cfg80211_get_chandef_type(chandef));
 
-       if (channel_type != NL80211_CHAN_NO_HT)
+       if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
                goto out;
 
-       ret = lbs_set_channel(priv, channel->hw_value);
+       ret = lbs_set_channel(priv, chandef->chan->hw_value);
 
  out:
        lbs_deb_leave_args(LBS_DEB_CFG80211, "ret %d", ret);
@@ -1734,7 +1734,7 @@ static void lbs_join_post(struct lbs_private *priv,
        /* Fake DS channel IE */
        *fake++ = WLAN_EID_DS_PARAMS;
        *fake++ = 1;
-       *fake++ = params->channel->hw_value;
+       *fake++ = params->chandef.chan->hw_value;
        /* Fake IBSS params IE */
        *fake++ = WLAN_EID_IBSS_PARAMS;
        *fake++ = 2;
@@ -1755,7 +1755,7 @@ static void lbs_join_post(struct lbs_private *priv,
        lbs_deb_hex(LBS_DEB_CFG80211, "IE", fake_ie, fake - fake_ie);
 
        bss = cfg80211_inform_bss(priv->wdev->wiphy,
-                                 params->channel,
+                                 params->chandef.chan,
                                  bssid,
                                  0,
                                  capability,
@@ -1833,7 +1833,7 @@ static int lbs_ibss_join_existing(struct lbs_private *priv,
        cmd.bss.beaconperiod = cpu_to_le16(params->beacon_interval);
        cmd.bss.ds.header.id = WLAN_EID_DS_PARAMS;
        cmd.bss.ds.header.len = 1;
-       cmd.bss.ds.channel = params->channel->hw_value;
+       cmd.bss.ds.channel = params->chandef.chan->hw_value;
        cmd.bss.ibss.header.id = WLAN_EID_IBSS_PARAMS;
        cmd.bss.ibss.header.len = 2;
        cmd.bss.ibss.atimwindow = 0;
@@ -1942,7 +1942,7 @@ static int lbs_ibss_start_new(struct lbs_private *priv,
        cmd.ibss.atimwindow = 0;
        cmd.ds.header.id = WLAN_EID_DS_PARAMS;
        cmd.ds.header.len = 1;
-       cmd.ds.channel = params->channel->hw_value;
+       cmd.ds.channel = params->chandef.chan->hw_value;
        /* Only v8 and below support setting probe delay */
        if (MRVL_FW_MAJOR_REV(priv->fwrelease) <= 8)
                cmd.probedelay = cpu_to_le16(CMD_SCAN_PROBE_DELAY_TIME);
@@ -1987,18 +1987,18 @@ static int lbs_join_ibss(struct wiphy *wiphy, struct net_device *dev,
 
        lbs_deb_enter(LBS_DEB_CFG80211);
 
-       if (!params->channel) {
+       if (!params->chandef.chan) {
                ret = -ENOTSUPP;
                goto out;
        }
 
-       ret = lbs_set_channel(priv, params->channel->hw_value);
+       ret = lbs_set_channel(priv, params->chandef.chan->hw_value);
        if (ret)
                goto out;
 
        /* Search if someone is beaconing. This assumes that the
         * bss list is populated already */
-       bss = cfg80211_get_bss(wiphy, params->channel, params->bssid,
+       bss = cfg80211_get_bss(wiphy, params->chandef.chan, params->bssid,
                params->ssid, params->ssid_len,
                WLAN_CAPABILITY_IBSS, WLAN_CAPABILITY_IBSS);
 
index 4cb234349fbfacc305b1565ed5f1a30ba16aa108..739309e70d8be7872e9272c9e25dcb7e3a5b2a4a 100644 (file)
@@ -588,17 +588,38 @@ static int if_sdio_prog_real(struct if_sdio_card *card,
        size = fw->size;
 
        while (size) {
-               ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
-               if (ret)
-                       goto release;
+               timeout = jiffies + HZ;
+               while (1) {
+                       ret = if_sdio_wait_status(card, FW_DL_READY_STATUS);
+                       if (ret)
+                               goto release;
 
-               req_size = sdio_readb(card->func, IF_SDIO_RD_BASE, &ret);
-               if (ret)
-                       goto release;
+                       req_size = sdio_readb(card->func, IF_SDIO_RD_BASE,
+                                       &ret);
+                       if (ret)
+                               goto release;
+
+                       req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1,
+                                       &ret) << 8;
+                       if (ret)
+                               goto release;
+
+                       /*
+                        * For SD8688 wait until the length is not 0, 1 or 2
+                        * before downloading the first FW block,
+                        * since BOOT code writes the register to indicate the
+                        * helper/FW download winner,
+                        * the value could be 1 or 2 (Func1 or Func2).
+                        */
+                       if ((size != fw->size) || (req_size > 2))
+                               break;
+                       if (time_after(jiffies, timeout)) {
+                               ret = -ETIMEDOUT;
+                               goto release;
+                       }
+                       mdelay(1);
+               }
 
-               req_size |= sdio_readb(card->func, IF_SDIO_RD_BASE + 1, &ret) << 8;
-               if (ret)
-                       goto release;
 /*
                lbs_deb_sdio("firmware wants %d bytes\n", (int)req_size);
 */
index 429ca3215fdbf3e0d48f82e3c1eb69381938fd46..2aa8a1aa1184fecf0c42c3bf4a57535f4380a4ad 100644 (file)
@@ -44,9 +44,9 @@ static int radios = 2;
 module_param(radios, int, 0444);
 MODULE_PARM_DESC(radios, "Number of simulated radios");
 
-static bool fake_hw_scan;
-module_param(fake_hw_scan, bool, 0444);
-MODULE_PARM_DESC(fake_hw_scan, "Install fake (no-op) hw-scan handler");
+static int channels = 1;
+module_param(channels, int, 0444);
+MODULE_PARM_DESC(channels, "Number of concurrent channels");
 
 /**
  * enum hwsim_regtest - the type of regulatory tests we offer
@@ -166,7 +166,9 @@ struct hwsim_vif_priv {
 static inline void hwsim_check_magic(struct ieee80211_vif *vif)
 {
        struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
-       WARN_ON(vp->magic != HWSIM_VIF_MAGIC);
+       WARN(vp->magic != HWSIM_VIF_MAGIC,
+            "Invalid VIF (%p) magic %#x, %pM, %d/%d\n",
+            vif, vp->magic, vif->addr, vif->type, vif->p2p);
 }
 
 static inline void hwsim_set_magic(struct ieee80211_vif *vif)
@@ -185,7 +187,7 @@ struct hwsim_sta_priv {
        u32 magic;
 };
 
-#define HWSIM_STA_MAGIC        0x6d537748
+#define HWSIM_STA_MAGIC        0x6d537749
 
 static inline void hwsim_check_sta_magic(struct ieee80211_sta *sta)
 {
@@ -205,6 +207,30 @@ static inline void hwsim_clear_sta_magic(struct ieee80211_sta *sta)
        sp->magic = 0;
 }
 
+struct hwsim_chanctx_priv {
+       u32 magic;
+};
+
+#define HWSIM_CHANCTX_MAGIC 0x6d53774a
+
+static inline void hwsim_check_chanctx_magic(struct ieee80211_chanctx_conf *c)
+{
+       struct hwsim_chanctx_priv *cp = (void *)c->drv_priv;
+       WARN_ON(cp->magic != HWSIM_CHANCTX_MAGIC);
+}
+
+static inline void hwsim_set_chanctx_magic(struct ieee80211_chanctx_conf *c)
+{
+       struct hwsim_chanctx_priv *cp = (void *)c->drv_priv;
+       cp->magic = HWSIM_CHANCTX_MAGIC;
+}
+
+static inline void hwsim_clear_chanctx_magic(struct ieee80211_chanctx_conf *c)
+{
+       struct hwsim_chanctx_priv *cp = (void *)c->drv_priv;
+       cp->magic = 0;
+}
+
 static struct class *hwsim_class;
 
 static struct net_device *hwsim_mon; /* global monitor netdev */
@@ -299,6 +325,13 @@ struct mac80211_hwsim_data {
 
        struct mac_address addresses[2];
 
+       struct ieee80211_channel *tmp_chan;
+       struct delayed_work roc_done;
+       struct delayed_work hw_scan;
+       struct cfg80211_scan_request *hw_scan_request;
+       struct ieee80211_vif *hw_scan_vif;
+       int scan_chan_idx;
+
        struct ieee80211_channel *channel;
        unsigned long beacon_int; /* in jiffies unit */
        unsigned int rx_filter;
@@ -396,7 +429,8 @@ static void mac80211_hwsim_set_tsf(struct ieee80211_hw *hw,
 }
 
 static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
-                                     struct sk_buff *tx_skb)
+                                     struct sk_buff *tx_skb,
+                                     struct ieee80211_channel *chan)
 {
        struct mac80211_hwsim_data *data = hw->priv;
        struct sk_buff *skb;
@@ -423,7 +457,7 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
        hdr->rt_tsft = __mac80211_hwsim_get_tsf(data);
        hdr->rt_flags = 0;
        hdr->rt_rate = txrate->bitrate / 5;
-       hdr->rt_channel = cpu_to_le16(data->channel->center_freq);
+       hdr->rt_channel = cpu_to_le16(chan->center_freq);
        flags = IEEE80211_CHAN_2GHZ;
        if (txrate->flags & IEEE80211_RATE_ERP_G)
                flags |= IEEE80211_CHAN_OFDM;
@@ -441,9 +475,9 @@ static void mac80211_hwsim_monitor_rx(struct ieee80211_hw *hw,
 }
 
 
-static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr)
+static void mac80211_hwsim_monitor_ack(struct ieee80211_channel *chan,
+                                      const u8 *addr)
 {
-       struct mac80211_hwsim_data *data = hw->priv;
        struct sk_buff *skb;
        struct hwsim_radiotap_hdr *hdr;
        u16 flags;
@@ -464,7 +498,7 @@ static void mac80211_hwsim_monitor_ack(struct ieee80211_hw *hw, const u8 *addr)
                                          (1 << IEEE80211_RADIOTAP_CHANNEL));
        hdr->rt_flags = 0;
        hdr->rt_rate = 0;
-       hdr->rt_channel = cpu_to_le16(data->channel->center_freq);
+       hdr->rt_channel = cpu_to_le16(chan->center_freq);
        flags = IEEE80211_CHAN_2GHZ;
        hdr->rt_chbitmask = cpu_to_le16(flags);
 
@@ -537,6 +571,7 @@ static bool mac80211_hwsim_addr_match(struct mac80211_hwsim_data *data,
        md.ret = false;
        md.addr = addr;
        ieee80211_iterate_active_interfaces_atomic(data->hw,
+                                                  IEEE80211_IFACE_ITER_NORMAL,
                                                   mac80211_hwsim_addr_iter,
                                                   &md);
 
@@ -556,12 +591,6 @@ static void mac80211_hwsim_tx_frame_nl(struct ieee80211_hw *hw,
        int i;
        struct hwsim_tx_rate tx_attempts[IEEE80211_TX_MAX_RATES];
 
-       if (data->idle) {
-               wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n");
-               dev_kfree_skb(my_skb);
-               return;
-       }
-
        if (data->ps != PS_DISABLED)
                hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
        /* If the queue contains MAX_QUEUE skb's drop some */
@@ -629,8 +658,38 @@ nla_put_failure:
        printk(KERN_DEBUG "mac80211_hwsim: error occurred in %s\n", __func__);
 }
 
+static bool hwsim_chans_compat(struct ieee80211_channel *c1,
+                              struct ieee80211_channel *c2)
+{
+       if (!c1 || !c2)
+               return false;
+
+       return c1->center_freq == c2->center_freq;
+}
+
+struct tx_iter_data {
+       struct ieee80211_channel *channel;
+       bool receive;
+};
+
+static void mac80211_hwsim_tx_iter(void *_data, u8 *addr,
+                                  struct ieee80211_vif *vif)
+{
+       struct tx_iter_data *data = _data;
+
+       if (!vif->chanctx_conf)
+               return;
+
+       if (!hwsim_chans_compat(data->channel,
+                               rcu_dereference(vif->chanctx_conf)->def.chan))
+               return;
+
+       data->receive = true;
+}
+
 static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
-                                         struct sk_buff *skb)
+                                         struct sk_buff *skb,
+                                         struct ieee80211_channel *chan)
 {
        struct mac80211_hwsim_data *data = hw->priv, *data2;
        bool ack = false;
@@ -639,15 +698,10 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
        struct ieee80211_rx_status rx_status;
        struct ieee80211_rate *txrate = ieee80211_get_tx_rate(hw, info);
 
-       if (data->idle) {
-               wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n");
-               return false;
-       }
-
        memset(&rx_status, 0, sizeof(rx_status));
-       rx_status.flag |= RX_FLAG_MACTIME_MPDU;
-       rx_status.freq = data->channel->center_freq;
-       rx_status.band = data->channel->band;
+       rx_status.flag |= RX_FLAG_MACTIME_START;
+       rx_status.freq = chan->center_freq;
+       rx_status.band = chan->band;
        rx_status.rate_idx = info->control.rates[0].idx;
        if (info->control.rates[0].flags & IEEE80211_TX_RC_MCS)
                rx_status.flag |= RX_FLAG_HT;
@@ -673,17 +727,35 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
        list_for_each_entry(data2, &hwsim_radios, list) {
                struct sk_buff *nskb;
                struct ieee80211_mgmt *mgmt;
+               struct tx_iter_data tx_iter_data = {
+                       .receive = false,
+                       .channel = chan,
+               };
 
                if (data == data2)
                        continue;
 
-               if (data2->idle || !data2->started ||
-                   !hwsim_ps_rx_ok(data2, skb) || !data2->channel ||
-                   data->channel->center_freq != data2->channel->center_freq ||
-                   !(data->group & data2->group))
+               if (!data2->started || (data2->idle && !data2->tmp_chan) ||
+                   !hwsim_ps_rx_ok(data2, skb))
                        continue;
 
-               nskb = skb_copy(skb, GFP_ATOMIC);
+               if (!(data->group & data2->group))
+                       continue;
+
+               if (!hwsim_chans_compat(chan, data2->tmp_chan) &&
+                   !hwsim_chans_compat(chan, data2->channel)) {
+                       ieee80211_iterate_active_interfaces_atomic(
+                               data2->hw, IEEE80211_IFACE_ITER_NORMAL,
+                               mac80211_hwsim_tx_iter, &tx_iter_data);
+                       if (!tx_iter_data.receive)
+                               continue;
+               }
+
+               /*
+                * reserve some space for our vendor and the normal
+                * radiotap header, since we're copying anyway
+                */
+               nskb = skb_copy_expand(skb, 64, 0, GFP_ATOMIC);
                if (nskb == NULL)
                        continue;
 
@@ -701,6 +773,33 @@ static bool mac80211_hwsim_tx_frame_no_nl(struct ieee80211_hw *hw,
                                (data->tsf_offset - data2->tsf_offset) +
                                24 * 8 * 10 / txrate->bitrate);
 
+#if 0
+               /*
+                * Don't enable this code by default as the OUI 00:00:00
+                * is registered to Xerox so we shouldn't use it here, it
+                * might find its way into pcap files.
+                * Note that this code requires the headroom in the SKB
+                * that was allocated earlier.
+                */
+               rx_status.vendor_radiotap_oui[0] = 0x00;
+               rx_status.vendor_radiotap_oui[1] = 0x00;
+               rx_status.vendor_radiotap_oui[2] = 0x00;
+               rx_status.vendor_radiotap_subns = 127;
+               /*
+                * Radiotap vendor namespaces can (and should) also be
+                * split into fields by using the standard radiotap
+                * presence bitmap mechanism. Use just BIT(0) here for
+                * the presence bitmap.
+                */
+               rx_status.vendor_radiotap_bitmap = BIT(0);
+               /* We have 8 bytes of (dummy) data */
+               rx_status.vendor_radiotap_len = 8;
+               /* For testing, also require it to be aligned */
+               rx_status.vendor_radiotap_align = 8;
+               /* push the data */
+               memcpy(skb_push(nskb, 8), "ABCDEFGH", 8);
+#endif
+
                memcpy(IEEE80211_SKB_RXCB(nskb), &rx_status, sizeof(rx_status));
                ieee80211_rx_irqsafe(data2->hw, nskb);
        }
@@ -713,18 +812,51 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
                              struct ieee80211_tx_control *control,
                              struct sk_buff *skb)
 {
+       struct mac80211_hwsim_data *data = hw->priv;
+       struct ieee80211_tx_info *txi = IEEE80211_SKB_CB(skb);
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       struct ieee80211_channel *channel;
        bool ack;
-       struct ieee80211_tx_info *txi;
        u32 _portid;
 
-       mac80211_hwsim_monitor_rx(hw, skb);
-
-       if (skb->len < 10) {
+       if (WARN_ON(skb->len < 10)) {
                /* Should not happen; just a sanity check for addr1 use */
                dev_kfree_skb(skb);
                return;
        }
 
+       if (channels == 1) {
+               channel = data->channel;
+       } else if (txi->hw_queue == 4) {
+               channel = data->tmp_chan;
+       } else {
+               chanctx_conf = rcu_dereference(txi->control.vif->chanctx_conf);
+               if (chanctx_conf)
+                       channel = chanctx_conf->def.chan;
+               else
+                       channel = NULL;
+       }
+
+       if (WARN(!channel, "TX w/o channel - queue = %d\n", txi->hw_queue)) {
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       if (data->idle && !data->tmp_chan) {
+               wiphy_debug(hw->wiphy, "Trying to TX when idle - reject\n");
+               dev_kfree_skb(skb);
+               return;
+       }
+
+       if (txi->control.vif)
+               hwsim_check_magic(txi->control.vif);
+       if (control->sta)
+               hwsim_check_sta_magic(control->sta);
+
+       txi->rate_driver_data[0] = channel;
+
+       mac80211_hwsim_monitor_rx(hw, skb, channel);
+
        /* wmediumd mode check */
        _portid = ACCESS_ONCE(wmediumd_portid);
 
@@ -732,15 +864,13 @@ static void mac80211_hwsim_tx(struct ieee80211_hw *hw,
                return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
 
        /* NO wmediumd detected, perfect medium simulation */
-       ack = mac80211_hwsim_tx_frame_no_nl(hw, skb);
+       ack = mac80211_hwsim_tx_frame_no_nl(hw, skb, channel);
 
        if (ack && skb->len >= 16) {
                struct ieee80211_hdr *hdr = (struct ieee80211_hdr *) skb->data;
-               mac80211_hwsim_monitor_ack(hw, hdr->addr2);
+               mac80211_hwsim_monitor_ack(channel, hdr->addr2);
        }
 
-       txi = IEEE80211_SKB_CB(skb);
-
        ieee80211_tx_info_clear_status(txi);
 
        /* frame was transmitted at most favorable rate at first attempt */
@@ -778,6 +908,13 @@ static int mac80211_hwsim_add_interface(struct ieee80211_hw *hw,
                    __func__, ieee80211_vif_type_p2p(vif),
                    vif->addr);
        hwsim_set_magic(vif);
+
+       vif->cab_queue = 0;
+       vif->hw_queue[IEEE80211_AC_VO] = 0;
+       vif->hw_queue[IEEE80211_AC_VI] = 1;
+       vif->hw_queue[IEEE80211_AC_BE] = 2;
+       vif->hw_queue[IEEE80211_AC_BK] = 3;
+
        return 0;
 }
 
@@ -807,14 +944,26 @@ static void mac80211_hwsim_remove_interface(
        hwsim_clear_magic(vif);
 }
 
+static void mac80211_hwsim_tx_frame(struct ieee80211_hw *hw,
+                                   struct sk_buff *skb,
+                                   struct ieee80211_channel *chan)
+{
+       u32 _pid = ACCESS_ONCE(wmediumd_portid);
+
+       mac80211_hwsim_monitor_rx(hw, skb, chan);
+
+       if (_pid)
+               return mac80211_hwsim_tx_frame_nl(hw, skb, _pid);
+
+       mac80211_hwsim_tx_frame_no_nl(hw, skb, chan);
+       dev_kfree_skb(skb);
+}
 
 static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
                                     struct ieee80211_vif *vif)
 {
        struct ieee80211_hw *hw = arg;
        struct sk_buff *skb;
-       struct ieee80211_tx_info *info;
-       u32 _portid;
 
        hwsim_check_magic(vif);
 
@@ -826,18 +975,9 @@ static void mac80211_hwsim_beacon_tx(void *arg, u8 *mac,
        skb = ieee80211_beacon_get(hw, vif);
        if (skb == NULL)
                return;
-       info = IEEE80211_SKB_CB(skb);
-
-       mac80211_hwsim_monitor_rx(hw, skb);
-
-       /* wmediumd mode check */
-       _portid = ACCESS_ONCE(wmediumd_portid);
-
-       if (_portid)
-               return mac80211_hwsim_tx_frame_nl(hw, skb, _portid);
 
-       mac80211_hwsim_tx_frame_no_nl(hw, skb);
-       dev_kfree_skb(skb);
+       mac80211_hwsim_tx_frame(hw, skb,
+                               rcu_dereference(vif->chanctx_conf)->def.chan);
 }
 
 
@@ -850,7 +990,8 @@ static void mac80211_hwsim_beacon(unsigned long arg)
                return;
 
        ieee80211_iterate_active_interfaces_atomic(
-               hw, mac80211_hwsim_beacon_tx, hw);
+               hw, IEEE80211_IFACE_ITER_NORMAL,
+               mac80211_hwsim_beacon_tx, hw);
 
        data->beacon_timer.expires = jiffies + data->beacon_int;
        add_timer(&data->beacon_timer);
@@ -877,7 +1018,7 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
        wiphy_debug(hw->wiphy,
                    "%s (freq=%d/%s idle=%d ps=%d smps=%s)\n",
                    __func__,
-                   conf->channel->center_freq,
+                   conf->channel ? conf->channel->center_freq : 0,
                    hwsim_chantypes[conf->channel_type],
                    !!(conf->flags & IEEE80211_CONF_IDLE),
                    !!(conf->flags & IEEE80211_CONF_PS),
@@ -886,6 +1027,9 @@ static int mac80211_hwsim_config(struct ieee80211_hw *hw, u32 changed)
        data->idle = !!(conf->flags & IEEE80211_CONF_IDLE);
 
        data->channel = conf->channel;
+
+       WARN_ON(data->channel && channels > 1);
+
        data->power_level = conf->power_level;
        if (!data->started || !data->beacon_int)
                del_timer(&data->beacon_timer);
@@ -963,15 +1107,17 @@ static void mac80211_hwsim_bss_info_changed(struct ieee80211_hw *hw,
        }
 
        if (changed & BSS_CHANGED_HT) {
-               wiphy_debug(hw->wiphy, "  HT: op_mode=0x%x, chantype=%s\n",
-                           info->ht_operation_mode,
-                           hwsim_chantypes[info->channel_type]);
+               wiphy_debug(hw->wiphy, "  HT: op_mode=0x%x\n",
+                           info->ht_operation_mode);
        }
 
        if (changed & BSS_CHANGED_BASIC_RATES) {
                wiphy_debug(hw->wiphy, "  BASIC_RATES: 0x%llx\n",
                            (unsigned long long) info->basic_rates);
        }
+
+       if (changed & BSS_CHANGED_TXPOWER)
+               wiphy_debug(hw->wiphy, "  TX Power: %d dBm\n", info->txpower);
 }
 
 static int mac80211_hwsim_sta_add(struct ieee80211_hw *hw,
@@ -1166,45 +1312,96 @@ static void mac80211_hwsim_flush(struct ieee80211_hw *hw, bool drop)
        /* Not implemented, queues only on kernel side */
 }
 
-struct hw_scan_done {
-       struct delayed_work w;
-       struct ieee80211_hw *hw;
-};
-
-static void hw_scan_done(struct work_struct *work)
+static void hw_scan_work(struct work_struct *work)
 {
-       struct hw_scan_done *hsd =
-               container_of(work, struct hw_scan_done, w.work);
+       struct mac80211_hwsim_data *hwsim =
+               container_of(work, struct mac80211_hwsim_data, hw_scan.work);
+       struct cfg80211_scan_request *req = hwsim->hw_scan_request;
+       int dwell, i;
+
+       mutex_lock(&hwsim->mutex);
+       if (hwsim->scan_chan_idx >= req->n_channels) {
+               wiphy_debug(hwsim->hw->wiphy, "hw scan complete\n");
+               ieee80211_scan_completed(hwsim->hw, false);
+               hwsim->hw_scan_request = NULL;
+               hwsim->hw_scan_vif = NULL;
+               hwsim->tmp_chan = NULL;
+               mutex_unlock(&hwsim->mutex);
+               return;
+       }
 
-       ieee80211_scan_completed(hsd->hw, false);
-       kfree(hsd);
+       wiphy_debug(hwsim->hw->wiphy, "hw scan %d MHz\n",
+                   req->channels[hwsim->scan_chan_idx]->center_freq);
+
+       hwsim->tmp_chan = req->channels[hwsim->scan_chan_idx];
+       if (hwsim->tmp_chan->flags & IEEE80211_CHAN_PASSIVE_SCAN ||
+           !req->n_ssids) {
+               dwell = 120;
+       } else {
+               dwell = 30;
+               /* send probes */
+               for (i = 0; i < req->n_ssids; i++) {
+                       struct sk_buff *probe;
+
+                       probe = ieee80211_probereq_get(hwsim->hw,
+                                                      hwsim->hw_scan_vif,
+                                                      req->ssids[i].ssid,
+                                                      req->ssids[i].ssid_len,
+                                                      req->ie, req->ie_len);
+                       if (!probe)
+                               continue;
+                       local_bh_disable();
+                       mac80211_hwsim_tx_frame(hwsim->hw, probe,
+                                               hwsim->tmp_chan);
+                       local_bh_enable();
+               }
+       }
+       ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan,
+                                    msecs_to_jiffies(dwell));
+       hwsim->scan_chan_idx++;
+       mutex_unlock(&hwsim->mutex);
 }
 
 static int mac80211_hwsim_hw_scan(struct ieee80211_hw *hw,
                                  struct ieee80211_vif *vif,
                                  struct cfg80211_scan_request *req)
 {
-       struct hw_scan_done *hsd = kzalloc(sizeof(*hsd), GFP_KERNEL);
-       int i;
-
-       if (!hsd)
-               return -ENOMEM;
+       struct mac80211_hwsim_data *hwsim = hw->priv;
 
-       hsd->hw = hw;
-       INIT_DELAYED_WORK(&hsd->w, hw_scan_done);
+       mutex_lock(&hwsim->mutex);
+       if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) {
+               mutex_unlock(&hwsim->mutex);
+               return -EBUSY;
+       }
+       hwsim->hw_scan_request = req;
+       hwsim->hw_scan_vif = vif;
+       hwsim->scan_chan_idx = 0;
+       mutex_unlock(&hwsim->mutex);
 
-       printk(KERN_DEBUG "hwsim hw_scan request\n");
-       for (i = 0; i < req->n_channels; i++)
-               printk(KERN_DEBUG "hwsim hw_scan freq %d\n",
-                       req->channels[i]->center_freq);
-       print_hex_dump(KERN_DEBUG, "scan IEs: ", DUMP_PREFIX_OFFSET,
-                       16, 1, req->ie, req->ie_len, 1);
+       wiphy_debug(hw->wiphy, "hwsim hw_scan request\n");
 
-       ieee80211_queue_delayed_work(hw, &hsd->w, 2 * HZ);
+       ieee80211_queue_delayed_work(hwsim->hw, &hwsim->hw_scan, 0);
 
        return 0;
 }
 
+static void mac80211_hwsim_cancel_hw_scan(struct ieee80211_hw *hw,
+                                         struct ieee80211_vif *vif)
+{
+       struct mac80211_hwsim_data *hwsim = hw->priv;
+
+       wiphy_debug(hw->wiphy, "hwsim cancel_hw_scan\n");
+
+       cancel_delayed_work_sync(&hwsim->hw_scan);
+
+       mutex_lock(&hwsim->mutex);
+       ieee80211_scan_completed(hwsim->hw, true);
+       hwsim->tmp_chan = NULL;
+       hwsim->hw_scan_request = NULL;
+       hwsim->hw_scan_vif = NULL;
+       mutex_unlock(&hwsim->mutex);
+}
+
 static void mac80211_hwsim_sw_scan(struct ieee80211_hw *hw)
 {
        struct mac80211_hwsim_data *hwsim = hw->priv;
@@ -1235,6 +1432,111 @@ static void mac80211_hwsim_sw_scan_complete(struct ieee80211_hw *hw)
        mutex_unlock(&hwsim->mutex);
 }
 
+static void hw_roc_done(struct work_struct *work)
+{
+       struct mac80211_hwsim_data *hwsim =
+               container_of(work, struct mac80211_hwsim_data, roc_done.work);
+
+       mutex_lock(&hwsim->mutex);
+       ieee80211_remain_on_channel_expired(hwsim->hw);
+       hwsim->tmp_chan = NULL;
+       mutex_unlock(&hwsim->mutex);
+
+       wiphy_debug(hwsim->hw->wiphy, "hwsim ROC expired\n");
+}
+
+static int mac80211_hwsim_roc(struct ieee80211_hw *hw,
+                             struct ieee80211_vif *vif,
+                             struct ieee80211_channel *chan,
+                             int duration)
+{
+       struct mac80211_hwsim_data *hwsim = hw->priv;
+
+       mutex_lock(&hwsim->mutex);
+       if (WARN_ON(hwsim->tmp_chan || hwsim->hw_scan_request)) {
+               mutex_unlock(&hwsim->mutex);
+               return -EBUSY;
+       }
+
+       hwsim->tmp_chan = chan;
+       mutex_unlock(&hwsim->mutex);
+
+       wiphy_debug(hw->wiphy, "hwsim ROC (%d MHz, %d ms)\n",
+                   chan->center_freq, duration);
+
+       ieee80211_ready_on_channel(hw);
+
+       ieee80211_queue_delayed_work(hw, &hwsim->roc_done,
+                                    msecs_to_jiffies(duration));
+       return 0;
+}
+
+static int mac80211_hwsim_croc(struct ieee80211_hw *hw)
+{
+       struct mac80211_hwsim_data *hwsim = hw->priv;
+
+       cancel_delayed_work_sync(&hwsim->roc_done);
+
+       mutex_lock(&hwsim->mutex);
+       hwsim->tmp_chan = NULL;
+       mutex_unlock(&hwsim->mutex);
+
+       wiphy_debug(hw->wiphy, "hwsim ROC canceled\n");
+
+       return 0;
+}
+
+static int mac80211_hwsim_add_chanctx(struct ieee80211_hw *hw,
+                                     struct ieee80211_chanctx_conf *ctx)
+{
+       hwsim_set_chanctx_magic(ctx);
+       wiphy_debug(hw->wiphy,
+                   "add channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
+                   ctx->def.chan->center_freq, ctx->def.width,
+                   ctx->def.center_freq1, ctx->def.center_freq2);
+       return 0;
+}
+
+static void mac80211_hwsim_remove_chanctx(struct ieee80211_hw *hw,
+                                         struct ieee80211_chanctx_conf *ctx)
+{
+       wiphy_debug(hw->wiphy,
+                   "remove channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
+                   ctx->def.chan->center_freq, ctx->def.width,
+                   ctx->def.center_freq1, ctx->def.center_freq2);
+       hwsim_check_chanctx_magic(ctx);
+       hwsim_clear_chanctx_magic(ctx);
+}
+
+static void mac80211_hwsim_change_chanctx(struct ieee80211_hw *hw,
+                                         struct ieee80211_chanctx_conf *ctx,
+                                         u32 changed)
+{
+       hwsim_check_chanctx_magic(ctx);
+       wiphy_debug(hw->wiphy,
+                   "change channel context control: %d MHz/width: %d/cfreqs:%d/%d MHz\n",
+                   ctx->def.chan->center_freq, ctx->def.width,
+                   ctx->def.center_freq1, ctx->def.center_freq2);
+}
+
+static int mac80211_hwsim_assign_vif_chanctx(struct ieee80211_hw *hw,
+                                            struct ieee80211_vif *vif,
+                                            struct ieee80211_chanctx_conf *ctx)
+{
+       hwsim_check_magic(vif);
+       hwsim_check_chanctx_magic(ctx);
+
+       return 0;
+}
+
+static void mac80211_hwsim_unassign_vif_chanctx(struct ieee80211_hw *hw,
+                                               struct ieee80211_vif *vif,
+                                               struct ieee80211_chanctx_conf *ctx)
+{
+       hwsim_check_magic(vif);
+       hwsim_check_chanctx_magic(ctx);
+}
+
 static struct ieee80211_ops mac80211_hwsim_ops =
 {
        .tx = mac80211_hwsim_tx,
@@ -1315,7 +1617,6 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
        struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
        struct sk_buff *skb;
        struct ieee80211_pspoll *pspoll;
-       u32 _portid;
 
        if (!vp->assoc)
                return;
@@ -1335,25 +1636,18 @@ static void hwsim_send_ps_poll(void *dat, u8 *mac, struct ieee80211_vif *vif)
        memcpy(pspoll->bssid, vp->bssid, ETH_ALEN);
        memcpy(pspoll->ta, mac, ETH_ALEN);
 
-       /* wmediumd mode check */
-       _portid = ACCESS_ONCE(wmediumd_portid);
-
-       if (_portid)
-               return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid);
-
-       if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb))
-               printk(KERN_DEBUG "%s: PS-poll frame not ack'ed\n", __func__);
-       dev_kfree_skb(skb);
+       rcu_read_lock();
+       mac80211_hwsim_tx_frame(data->hw, skb,
+                               rcu_dereference(vif->chanctx_conf)->def.chan);
+       rcu_read_unlock();
 }
 
-
 static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
                                struct ieee80211_vif *vif, int ps)
 {
        struct hwsim_vif_priv *vp = (void *)vif->drv_priv;
        struct sk_buff *skb;
        struct ieee80211_hdr *hdr;
-       u32 _portid;
 
        if (!vp->assoc)
                return;
@@ -1374,15 +1668,10 @@ static void hwsim_send_nullfunc(struct mac80211_hwsim_data *data, u8 *mac,
        memcpy(hdr->addr2, mac, ETH_ALEN);
        memcpy(hdr->addr3, vp->bssid, ETH_ALEN);
 
-       /* wmediumd mode check */
-       _portid = ACCESS_ONCE(wmediumd_portid);
-
-       if (_portid)
-               return mac80211_hwsim_tx_frame_nl(data->hw, skb, _portid);
-
-       if (!mac80211_hwsim_tx_frame_no_nl(data->hw, skb))
-               printk(KERN_DEBUG "%s: nullfunc frame not ack'ed\n", __func__);
-       dev_kfree_skb(skb);
+       rcu_read_lock();
+       mac80211_hwsim_tx_frame(data->hw, skb,
+                               rcu_dereference(vif->chanctx_conf)->def.chan);
+       rcu_read_unlock();
 }
 
 
@@ -1423,14 +1712,17 @@ static int hwsim_fops_ps_write(void *dat, u64 val)
 
        if (val == PS_MANUAL_POLL) {
                ieee80211_iterate_active_interfaces(data->hw,
+                                                   IEEE80211_IFACE_ITER_NORMAL,
                                                    hwsim_send_ps_poll, data);
                data->ps_poll_pending = true;
        } else if (old_ps == PS_DISABLED && val != PS_DISABLED) {
                ieee80211_iterate_active_interfaces(data->hw,
+                                                   IEEE80211_IFACE_ITER_NORMAL,
                                                    hwsim_send_nullfunc_ps,
                                                    data);
        } else if (old_ps != PS_DISABLED && val == PS_DISABLED) {
                ieee80211_iterate_active_interfaces(data->hw,
+                                                   IEEE80211_IFACE_ITER_NORMAL,
                                                    hwsim_send_nullfunc_no_ps,
                                                    data);
        }
@@ -1551,7 +1843,8 @@ static int hwsim_tx_info_frame_received_nl(struct sk_buff *skb_2,
           (hwsim_flags & HWSIM_TX_STAT_ACK)) {
                if (skb->len >= 16) {
                        hdr = (struct ieee80211_hdr *) skb->data;
-                       mac80211_hwsim_monitor_ack(data2->hw, hdr->addr2);
+                       mac80211_hwsim_monitor_ack(txi->rate_driver_data[0],
+                                                  hdr->addr2);
                }
                txi->flags |= IEEE80211_TX_STAT_ACK;
        }
@@ -1566,7 +1859,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
                                          struct genl_info *info)
 {
 
-       struct mac80211_hwsim_data  *data2;
+       struct mac80211_hwsim_data *data2;
        struct ieee80211_rx_status rx_status;
        struct mac_address *dst;
        int frame_data_len;
@@ -1574,9 +1867,9 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
        struct sk_buff *skb = NULL;
 
        if (!info->attrs[HWSIM_ATTR_ADDR_RECEIVER] ||
-          !info->attrs[HWSIM_ATTR_FRAME] ||
-          !info->attrs[HWSIM_ATTR_RX_RATE] ||
-          !info->attrs[HWSIM_ATTR_SIGNAL])
+           !info->attrs[HWSIM_ATTR_FRAME] ||
+           !info->attrs[HWSIM_ATTR_RX_RATE] ||
+           !info->attrs[HWSIM_ATTR_SIGNAL])
                goto out;
 
        dst = (struct mac_address *)nla_data(
@@ -1604,7 +1897,7 @@ static int hwsim_cloned_frame_received_nl(struct sk_buff *skb_2,
 
        /* check if radio is configured properly */
 
-       if (data2->idle || !data2->started || !data2->channel)
+       if (data2->idle || !data2->started)
                goto out;
 
        /*A frame is received from user space*/
@@ -1688,6 +1981,11 @@ static struct notifier_block hwsim_netlink_notifier = {
 static int hwsim_init_netlink(void)
 {
        int rc;
+
+       /* userspace test API hasn't been adjusted for multi-channel */
+       if (channels > 1)
+               return 0;
+
        printk(KERN_INFO "mac80211_hwsim: initializing netlink\n");
 
        rc = genl_register_family_with_ops(&hwsim_genl_family,
@@ -1710,6 +2008,10 @@ static void hwsim_exit_netlink(void)
 {
        int ret;
 
+       /* userspace test API hasn't been adjusted for multi-channel */
+       if (channels > 1)
+               return;
+
        printk(KERN_INFO "mac80211_hwsim: closing netlink\n");
        /* unregister the notifier */
        netlink_unregister_notifier(&hwsim_netlink_notifier);
@@ -1732,7 +2034,7 @@ static const struct ieee80211_iface_limit hwsim_if_limits[] = {
        { .max = 1, .types = BIT(NL80211_IFTYPE_P2P_DEVICE) },
 };
 
-static const struct ieee80211_iface_combination hwsim_if_comb = {
+static struct ieee80211_iface_combination hwsim_if_comb = {
        .limits = hwsim_if_limits,
        .n_limits = ARRAY_SIZE(hwsim_if_limits),
        .max_interfaces = 2048,
@@ -1750,10 +2052,30 @@ static int __init init_mac80211_hwsim(void)
        if (radios < 1 || radios > 100)
                return -EINVAL;
 
-       if (fake_hw_scan) {
+       if (channels < 1)
+               return -EINVAL;
+
+       if (channels > 1) {
+               hwsim_if_comb.num_different_channels = channels;
                mac80211_hwsim_ops.hw_scan = mac80211_hwsim_hw_scan;
+               mac80211_hwsim_ops.cancel_hw_scan =
+                       mac80211_hwsim_cancel_hw_scan;
                mac80211_hwsim_ops.sw_scan_start = NULL;
                mac80211_hwsim_ops.sw_scan_complete = NULL;
+               mac80211_hwsim_ops.remain_on_channel =
+                       mac80211_hwsim_roc;
+               mac80211_hwsim_ops.cancel_remain_on_channel =
+                       mac80211_hwsim_croc;
+               mac80211_hwsim_ops.add_chanctx =
+                       mac80211_hwsim_add_chanctx;
+               mac80211_hwsim_ops.remove_chanctx =
+                       mac80211_hwsim_remove_chanctx;
+               mac80211_hwsim_ops.change_chanctx =
+                       mac80211_hwsim_change_chanctx;
+               mac80211_hwsim_ops.assign_vif_chanctx =
+                       mac80211_hwsim_assign_vif_chanctx;
+               mac80211_hwsim_ops.unassign_vif_chanctx =
+                       mac80211_hwsim_unassign_vif_chanctx;
        }
 
        spin_lock_init(&hwsim_radio_lock);
@@ -1803,13 +2125,18 @@ static int __init init_mac80211_hwsim(void)
                hw->wiphy->iface_combinations = &hwsim_if_comb;
                hw->wiphy->n_iface_combinations = 1;
 
-               if (fake_hw_scan) {
+               if (channels > 1) {
                        hw->wiphy->max_scan_ssids = 255;
                        hw->wiphy->max_scan_ie_len = IEEE80211_MAX_DATA_LEN;
+                       hw->wiphy->max_remain_on_channel_duration = 1000;
                }
 
+               INIT_DELAYED_WORK(&data->roc_done, hw_roc_done);
+               INIT_DELAYED_WORK(&data->hw_scan, hw_scan_work);
+
                hw->channel_change_time = 1;
-               hw->queues = 4;
+               hw->queues = 5;
+               hw->offchannel_tx_hw_queue = 4;
                hw->wiphy->interface_modes =
                        BIT(NL80211_IFTYPE_STATION) |
                        BIT(NL80211_IFTYPE_AP) |
@@ -1824,7 +2151,8 @@ static int __init init_mac80211_hwsim(void)
                            IEEE80211_HW_SUPPORTS_STATIC_SMPS |
                            IEEE80211_HW_SUPPORTS_DYNAMIC_SMPS |
                            IEEE80211_HW_AMPDU_AGGREGATION |
-                           IEEE80211_HW_WANT_MONITOR_VIF;
+                           IEEE80211_HW_WANT_MONITOR_VIF |
+                           IEEE80211_HW_QUEUE_CONTROL;
 
                hw->wiphy->flags |= WIPHY_FLAG_SUPPORTS_TDLS |
                                    WIPHY_FLAG_HAS_REMAIN_ON_CHANNEL;
@@ -1874,6 +2202,34 @@ static int __init init_mac80211_hwsim(void)
                        sband->ht_cap.mcs.tx_params = IEEE80211_HT_MCS_TX_DEFINED;
 
                        hw->wiphy->bands[band] = sband;
+
+                       if (channels == 1)
+                               continue;
+
+                       sband->vht_cap.vht_supported = true;
+                       sband->vht_cap.cap =
+                               IEEE80211_VHT_CAP_MAX_MPDU_LENGTH_11454 |
+                               IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ |
+                               IEEE80211_VHT_CAP_RXLDPC |
+                               IEEE80211_VHT_CAP_SHORT_GI_80 |
+                               IEEE80211_VHT_CAP_SHORT_GI_160 |
+                               IEEE80211_VHT_CAP_TXSTBC |
+                               IEEE80211_VHT_CAP_RXSTBC_1 |
+                               IEEE80211_VHT_CAP_RXSTBC_2 |
+                               IEEE80211_VHT_CAP_RXSTBC_3 |
+                               IEEE80211_VHT_CAP_RXSTBC_4 |
+                               IEEE80211_VHT_CAP_MAX_A_MPDU_LENGTH_EXPONENT;
+                       sband->vht_cap.vht_mcs.rx_mcs_map =
+                               cpu_to_le16(IEEE80211_VHT_MCS_SUPPORT_0_8 << 0 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_8 << 2 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 4 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_8 << 6 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_8 << 8 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 10 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_9 << 12 |
+                                           IEEE80211_VHT_MCS_SUPPORT_0_8 << 14);
+                       sband->vht_cap.vht_mcs.tx_mcs_map =
+                               sband->vht_cap.vht_mcs.rx_mcs_map;
                }
                /* By default all radios are belonging to the first group */
                data->group = 1;
index 395f1bfd41027f788901b62b5ef4621ac019956d..68d52cfc1ebd250a55a43c8b641344d7d6999461 100644 (file)
@@ -197,7 +197,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                                       ra_list_flags);
                mwifiex_11n_form_amsdu_pkt(skb_aggr, skb_src, &pad);
 
-               mwifiex_write_data_complete(adapter, skb_src, 0);
+               mwifiex_write_data_complete(adapter, skb_src, 0, 0);
 
                spin_lock_irqsave(&priv->wmm.ra_list_spinlock, ra_list_flags);
 
@@ -256,7 +256,7 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                if (!mwifiex_is_ralist_valid(priv, pra_list, ptrindex)) {
                        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                               ra_list_flags);
-                       mwifiex_write_data_complete(adapter, skb_aggr, -1);
+                       mwifiex_write_data_complete(adapter, skb_aggr, 1, -1);
                        return -1;
                }
                if (GET_BSS_ROLE(priv) == MWIFIEX_BSS_ROLE_STA &&
@@ -282,13 +282,13 @@ mwifiex_11n_aggregate_pkt(struct mwifiex_private *priv,
                dev_err(adapter->dev, "%s: host_to_card failed: %#x\n",
                        __func__, ret);
                adapter->dbg.num_tx_host_to_card_failure++;
-               mwifiex_write_data_complete(adapter, skb_aggr, ret);
+               mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
                return 0;
        case -EINPROGRESS:
                adapter->data_sent = false;
                break;
        case 0:
-               mwifiex_write_data_complete(adapter, skb_aggr, ret);
+               mwifiex_write_data_complete(adapter, skb_aggr, 1, ret);
                break;
        default:
                break;
index 8e384fae3e68a840c274498c2376ab3423d61e89..b2e27723f8016817673cd6890b8546a693521fb9 100644 (file)
@@ -1,7 +1,6 @@
 config MWIFIEX
        tristate "Marvell WiFi-Ex Driver"
        depends on CFG80211
-       select LIB80211
        ---help---
          This adds support for wireless adapters based on Marvell
          802.11n chipsets.
index fdb1eb861021287b5c6f9f2aa30ab35601108be3..3b1c27712ad9b92c2092b987c861f0b02716dbea 100644 (file)
@@ -180,10 +180,8 @@ mwifiex_form_mgmt_frame(struct sk_buff *skb, const u8 *buf, size_t len)
 static int
 mwifiex_cfg80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                         struct ieee80211_channel *chan, bool offchan,
-                        enum nl80211_channel_type channel_type,
-                        bool channel_type_valid, unsigned int wait,
-                        const u8 *buf, size_t len, bool no_cck,
-                        bool dont_wait_for_ack, u64 *cookie)
+                        unsigned int wait, const u8 *buf, size_t len,
+                        bool no_cck, bool dont_wait_for_ack, u64 *cookie)
 {
        struct sk_buff *skb;
        u16 pkt_len;
@@ -253,7 +251,6 @@ static int
 mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
                                   struct wireless_dev *wdev,
                                   struct ieee80211_channel *chan,
-                                  enum nl80211_channel_type channel_type,
                                   unsigned int duration, u64 *cookie)
 {
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(wdev->netdev);
@@ -271,15 +268,14 @@ mwifiex_cfg80211_remain_on_channel(struct wiphy *wiphy,
        }
 
        ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_SET, chan,
-                                        &channel_type, duration);
+                                        duration);
 
        if (!ret) {
                *cookie = random32() | 1;
                priv->roc_cfg.cookie = *cookie;
                priv->roc_cfg.chan = *chan;
-               priv->roc_cfg.chan_type = channel_type;
 
-               cfg80211_ready_on_channel(wdev, *cookie, chan, channel_type,
+               cfg80211_ready_on_channel(wdev, *cookie, chan,
                                          duration, GFP_ATOMIC);
 
                wiphy_dbg(wiphy, "info: ROC, cookie = 0x%llx\n", *cookie);
@@ -302,13 +298,11 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
                return -ENOENT;
 
        ret = mwifiex_remain_on_chan_cfg(priv, HostCmd_ACT_GEN_REMOVE,
-                                        &priv->roc_cfg.chan,
-                                        &priv->roc_cfg.chan_type, 0);
+                                        &priv->roc_cfg.chan, 0);
 
        if (!ret) {
                cfg80211_remain_on_channel_expired(wdev, cookie,
                                                   &priv->roc_cfg.chan,
-                                                  priv->roc_cfg.chan_type,
                                                   GFP_ATOMIC);
 
                memset(&priv->roc_cfg, 0, sizeof(struct mwifiex_roc_cfg));
@@ -324,6 +318,7 @@ mwifiex_cfg80211_cancel_remain_on_channel(struct wiphy *wiphy,
  */
 static int
 mwifiex_cfg80211_set_tx_power(struct wiphy *wiphy,
+                             struct wireless_dev *wdev,
                              enum nl80211_tx_power_setting type,
                              int mbm)
 {
@@ -1296,21 +1291,23 @@ static int mwifiex_cfg80211_start_ap(struct wiphy *wiphy,
                return -EINVAL;
        }
 
-       bss_cfg->channel =
-           (u8)ieee80211_frequency_to_channel(params->channel->center_freq);
+       bss_cfg->channel = ieee80211_frequency_to_channel(
+                               params->chandef.chan->center_freq);
 
        /* Set appropriate bands */
-       if (params->channel->band == IEEE80211_BAND_2GHZ) {
+       if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) {
                bss_cfg->band_cfg = BAND_CONFIG_BG;
 
-               if (params->channel_type == NL80211_CHAN_NO_HT)
+               if (cfg80211_get_chandef_type(&params->chandef) ==
+                                               NL80211_CHAN_NO_HT)
                        config_bands = BAND_B | BAND_G;
                else
                        config_bands = BAND_B | BAND_G | BAND_GN;
        } else {
                bss_cfg->band_cfg = BAND_CONFIG_A;
 
-               if (params->channel_type == NL80211_CHAN_NO_HT)
+               if (cfg80211_get_chandef_type(&params->chandef) ==
+                                               NL80211_CHAN_NO_HT)
                        config_bands = BAND_A;
                else
                        config_bands = BAND_AN | BAND_A;
@@ -1683,7 +1680,7 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
        int index = 0, i;
        u8 config_bands = 0;
 
-       if (params->channel->band == IEEE80211_BAND_2GHZ) {
+       if (params->chandef.chan->band == IEEE80211_BAND_2GHZ) {
                if (!params->basic_rates) {
                        config_bands = BAND_B | BAND_G;
                } else {
@@ -1708,10 +1705,12 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
                        }
                }
 
-               if (params->channel_type != NL80211_CHAN_NO_HT)
+               if (cfg80211_get_chandef_type(&params->chandef) !=
+                                               NL80211_CHAN_NO_HT)
                        config_bands |= BAND_GN;
        } else {
-               if (params->channel_type == NL80211_CHAN_NO_HT)
+               if (cfg80211_get_chandef_type(&params->chandef) !=
+                                               NL80211_CHAN_NO_HT)
                        config_bands = BAND_A;
                else
                        config_bands = BAND_AN | BAND_A;
@@ -1728,9 +1727,10 @@ static int mwifiex_set_ibss_params(struct mwifiex_private *priv,
        }
 
        adapter->sec_chan_offset =
-               mwifiex_chan_type_to_sec_chan_offset(params->channel_type);
-       priv->adhoc_channel =
-               ieee80211_frequency_to_channel(params->channel->center_freq);
+               mwifiex_chan_type_to_sec_chan_offset(
+                       cfg80211_get_chandef_type(&params->chandef));
+       priv->adhoc_channel = ieee80211_frequency_to_channel(
+                               params->chandef.chan->center_freq);
 
        wiphy_dbg(wiphy, "info: set ibss band %d, chan %d, chan offset %d\n",
                  config_bands, priv->adhoc_channel, adapter->sec_chan_offset);
@@ -1764,7 +1764,8 @@ mwifiex_cfg80211_join_ibss(struct wiphy *wiphy, struct net_device *dev,
 
        ret = mwifiex_cfg80211_assoc(priv, params->ssid_len, params->ssid,
                                     params->bssid, priv->bss_mode,
-                                    params->channel, NULL, params->privacy);
+                                    params->chandef.chan, NULL,
+                                    params->privacy);
 done:
        if (!ret) {
                cfg80211_ibss_joined(priv->netdev, priv->cfg_bssid, GFP_KERNEL);
@@ -2080,8 +2081,8 @@ struct wireless_dev *mwifiex_add_virtual_intf(struct wiphy *wiphy,
                return ERR_PTR(-EINVAL);
        }
 
-       dev = alloc_netdev_mq(sizeof(struct mwifiex_private *), name,
-                             ether_setup, 1);
+       dev = alloc_netdev_mqs(sizeof(struct mwifiex_private *), name,
+                              ether_setup, IEEE80211_NUM_ACS, 1);
        if (!dev) {
                wiphy_err(wiphy, "no memory available for netdevice\n");
                priv->bss_mode = NL80211_IFTYPE_UNSPECIFIED;
@@ -2143,8 +2144,7 @@ int mwifiex_del_virtual_intf(struct wiphy *wiphy, struct wireless_dev *wdev)
        mwifiex_dev_debugfs_remove(priv);
 #endif
 
-       if (!netif_queue_stopped(priv->netdev))
-               netif_stop_queue(priv->netdev);
+       mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
 
        if (netif_carrier_ok(priv->netdev))
                netif_carrier_off(priv->netdev);
index be52a0a8d645b322643e4d83b07c2be7f5d3adc6..5f438e6c2155e6e8f103ae708791a1be2c1cedff 100644 (file)
@@ -949,6 +949,9 @@ mwifiex_cmd_timeout_func(unsigned long function_context)
        }
        if (adapter->hw_status == MWIFIEX_HW_STATUS_INITIALIZING)
                mwifiex_init_fw_complete(adapter);
+
+       if (adapter->if_ops.card_reset)
+               adapter->if_ops.card_reset(adapter);
 }
 
 /*
index a870b5885c09364872c597108f019135828d23bf..46e34aa65d1c2dec171e99c5156c57ecd5905a11 100644 (file)
@@ -178,6 +178,7 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
                (struct mwifiex_private *) file->private_data;
        struct net_device *netdev = priv->netdev;
        struct netdev_hw_addr *ha;
+       struct netdev_queue *txq;
        unsigned long page = get_zeroed_page(GFP_KERNEL);
        char *p = (char *) page, fmt[64];
        struct mwifiex_bss_info info;
@@ -229,8 +230,13 @@ mwifiex_info_read(struct file *file, char __user *ubuf,
        p += sprintf(p, "num_rx_pkts_err = %lu\n", priv->stats.rx_errors);
        p += sprintf(p, "carrier %s\n", ((netif_carrier_ok(priv->netdev))
                                         ? "on" : "off"));
-       p += sprintf(p, "tx queue %s\n", ((netif_queue_stopped(priv->netdev))
-                                         ? "stopped" : "started"));
+       p += sprintf(p, "tx queue");
+       for (i = 0; i < netdev->num_tx_queues; i++) {
+               txq = netdev_get_tx_queue(netdev, i);
+               p += sprintf(p, " %d:%s", i, netif_tx_queue_stopped(txq) ?
+                            "stopped" : "started");
+       }
+       p += sprintf(p, "\n");
 
        ret = simple_read_from_buffer(ubuf, count, ppos, (char *) page,
                                      (unsigned long) p - page);
index 482faace79005caf4c01b21de5794f2493c72445..39f03ce5a5b1cf50bfde4ec291438bc828a2dc22 100644 (file)
@@ -388,9 +388,17 @@ void mwifiex_wake_up_net_dev_queue(struct net_device *netdev,
                                        struct mwifiex_adapter *adapter)
 {
        unsigned long dev_queue_flags;
+       unsigned int i;
 
        spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags);
-       netif_tx_wake_all_queues(netdev);
+
+       for (i = 0; i < netdev->num_tx_queues; i++) {
+               struct netdev_queue *txq = netdev_get_tx_queue(netdev, i);
+
+               if (netif_tx_queue_stopped(txq))
+                       netif_tx_wake_queue(txq);
+       }
+
        spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags);
 }
 
@@ -401,9 +409,17 @@ void mwifiex_stop_net_dev_queue(struct net_device *netdev,
                                        struct mwifiex_adapter *adapter)
 {
        unsigned long dev_queue_flags;
+       unsigned int i;
 
        spin_lock_irqsave(&adapter->queue_lock, dev_queue_flags);
-       netif_tx_stop_all_queues(netdev);
+
+       for (i = 0; i < netdev->num_tx_queues; i++) {
+               struct netdev_queue *txq = netdev_get_tx_queue(netdev, i);
+
+               if (!netif_tx_queue_stopped(txq))
+                       netif_tx_stop_queue(txq);
+       }
+
        spin_unlock_irqrestore(&adapter->queue_lock, dev_queue_flags);
 }
 
index 7b0858af8f5d804d05ae6c8ebd4bc20990a6ffed..88664ae667ba65ea18e9c27410f26095e1931309 100644 (file)
@@ -721,8 +721,7 @@ int mwifiex_ret_802_11_associate(struct mwifiex_private *priv,
 
        if (!netif_carrier_ok(priv->netdev))
                netif_carrier_on(priv->netdev);
-       if (netif_queue_stopped(priv->netdev))
-               netif_wake_queue(priv->netdev);
+       mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
 
        if (priv->sec_info.wpa_enabled || priv->sec_info.wpa2_enabled)
                priv->scan_block = true;
@@ -1238,8 +1237,7 @@ int mwifiex_ret_802_11_ad_hoc(struct mwifiex_private *priv,
 
        if (!netif_carrier_ok(priv->netdev))
                netif_carrier_on(priv->netdev);
-       if (netif_queue_stopped(priv->netdev))
-               netif_wake_queue(priv->netdev);
+       mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
 
        mwifiex_save_curr_bcn(priv);
 
index 1df767bc8b6eb1efd34f2cb655698caa26453146..9c802ede9c3b94cb56f385e7c5c40699d0c2ee9f 100644 (file)
@@ -282,6 +282,7 @@ exit_main_proc:
                mwifiex_shutdown_drv(adapter);
        return ret;
 }
+EXPORT_SYMBOL_GPL(mwifiex_main_process);
 
 /*
  * This function frees the adapter structure.
@@ -411,49 +412,6 @@ static int mwifiex_init_hw_fw(struct mwifiex_adapter *adapter)
        return ret;
 }
 
-/*
- * This function fills a driver buffer.
- *
- * The function associates a given SKB with the provided driver buffer
- * and also updates some of the SKB parameters, including IP header,
- * priority and timestamp.
- */
-static void
-mwifiex_fill_buffer(struct sk_buff *skb)
-{
-       struct ethhdr *eth;
-       struct iphdr *iph;
-       struct timeval tv;
-       u8 tid = 0;
-
-       eth = (struct ethhdr *) skb->data;
-       switch (eth->h_proto) {
-       case __constant_htons(ETH_P_IP):
-               iph = ip_hdr(skb);
-               tid = IPTOS_PREC(iph->tos);
-               pr_debug("data: packet type ETH_P_IP: %04x, tid=%#x prio=%#x\n",
-                        eth->h_proto, tid, skb->priority);
-               break;
-       case __constant_htons(ETH_P_ARP):
-               pr_debug("data: ARP packet: %04x\n", eth->h_proto);
-       default:
-               break;
-       }
-/* Offset for TOS field in the IP header */
-#define IPTOS_OFFSET 5
-       tid = (tid >> IPTOS_OFFSET);
-       skb->priority = tid;
-       /* Record the current time the packet was queued; used to
-          determine the amount of time the packet was queued in
-          the driver before it was sent to the firmware.
-          The delay is then sent along with the packet to the
-          firmware for aggregate delay calculation for stats and
-          MSDU lifetime expiry.
-        */
-       do_gettimeofday(&tv);
-       skb->tstamp = timeval_to_ktime(tv);
-}
-
 /*
  * CFG802.11 network device handler for open.
  *
@@ -488,17 +446,23 @@ mwifiex_close(struct net_device *dev)
  */
 int mwifiex_queue_tx_pkt(struct mwifiex_private *priv, struct sk_buff *skb)
 {
-       mwifiex_wmm_add_buf_txqueue(priv, skb);
+       struct netdev_queue *txq;
+       int index = mwifiex_1d_to_wmm_queue[skb->priority];
+
+       if (atomic_inc_return(&priv->wmm_tx_pending[index]) >= MAX_TX_PENDING) {
+               txq = netdev_get_tx_queue(priv->netdev, index);
+               if (!netif_tx_queue_stopped(txq)) {
+                       netif_tx_stop_queue(txq);
+                       dev_dbg(priv->adapter->dev, "stop queue: %d\n", index);
+               }
+       }
+
        atomic_inc(&priv->adapter->tx_pending);
+       mwifiex_wmm_add_buf_txqueue(priv, skb);
 
        if (priv->adapter->scan_delay_cnt)
                atomic_set(&priv->adapter->is_tx_received, true);
 
-       if (atomic_read(&priv->adapter->tx_pending) >= MAX_TX_PENDING) {
-               mwifiex_set_trans_start(priv->netdev);
-               mwifiex_stop_net_dev_queue(priv->netdev, priv->adapter);
-       }
-
        queue_work(priv->adapter->workqueue, &priv->adapter->main_work);
 
        return 0;
@@ -513,6 +477,7 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        struct mwifiex_private *priv = mwifiex_netdev_get_priv(dev);
        struct sk_buff *new_skb;
        struct mwifiex_txinfo *tx_info;
+       struct timeval tv;
 
        dev_dbg(priv->adapter->dev, "data: %lu BSS(%d-%d): Data <= kernel\n",
                jiffies, priv->bss_type, priv->bss_num);
@@ -550,7 +515,16 @@ mwifiex_hard_start_xmit(struct sk_buff *skb, struct net_device *dev)
        tx_info = MWIFIEX_SKB_TXCB(skb);
        tx_info->bss_num = priv->bss_num;
        tx_info->bss_type = priv->bss_type;
-       mwifiex_fill_buffer(skb);
+
+       /* Record the current time the packet was queued; used to
+        * determine the amount of time the packet was queued in
+        * the driver before it was sent to the firmware.
+        * The delay is then sent along with the packet to the
+        * firmware for aggregate delay calculation for stats and
+        * MSDU lifetime expiry.
+        */
+       do_gettimeofday(&tv);
+       skb->tstamp = timeval_to_ktime(tv);
 
        mwifiex_queue_tx_pkt(priv, skb);
 
@@ -630,6 +604,13 @@ static struct net_device_stats *mwifiex_get_stats(struct net_device *dev)
        return &priv->stats;
 }
 
+static u16
+mwifiex_netdev_select_wmm_queue(struct net_device *dev, struct sk_buff *skb)
+{
+       skb->priority = cfg80211_classify8021d(skb);
+       return mwifiex_1d_to_wmm_queue[skb->priority];
+}
+
 /* Network device handlers */
 static const struct net_device_ops mwifiex_netdev_ops = {
        .ndo_open = mwifiex_open,
@@ -639,6 +620,7 @@ static const struct net_device_ops mwifiex_netdev_ops = {
        .ndo_tx_timeout = mwifiex_tx_timeout,
        .ndo_get_stats = mwifiex_get_stats,
        .ndo_set_rx_mode = mwifiex_set_multicast_list,
+       .ndo_select_queue = mwifiex_netdev_select_wmm_queue,
 };
 
 /*
@@ -838,9 +820,7 @@ int mwifiex_remove_card(struct mwifiex_adapter *adapter, struct semaphore *sem)
        for (i = 0; i < adapter->priv_num; i++) {
                priv = adapter->priv[i];
                if (priv && priv->netdev) {
-                       if (!netif_queue_stopped(priv->netdev))
-                               mwifiex_stop_net_dev_queue(priv->netdev,
-                                                          adapter);
+                       mwifiex_stop_net_dev_queue(priv->netdev, adapter);
                        if (netif_carrier_ok(priv->netdev))
                                netif_carrier_off(priv->netdev);
                }
index 81f8772dcb07c00eff281ef0632f1025fe0009bb..1b3cfc82194081606e21988f7dbc03a53c854df7 100644 (file)
@@ -371,7 +371,6 @@ struct wps {
 struct mwifiex_roc_cfg {
        u64 cookie;
        struct ieee80211_channel chan;
-       enum nl80211_channel_type chan_type;
 };
 
 struct mwifiex_adapter;
@@ -440,6 +439,7 @@ struct mwifiex_private {
        u8 wmm_enabled;
        u8 wmm_qosinfo;
        struct mwifiex_wmm_desc wmm;
+       atomic_t wmm_tx_pending[IEEE80211_NUM_ACS];
        struct list_head sta_list;
        /* spin lock for associated station list */
        spinlock_t sta_list_spinlock;
@@ -600,6 +600,7 @@ struct mwifiex_if_ops {
        int (*event_complete) (struct mwifiex_adapter *, struct sk_buff *);
        int (*data_complete) (struct mwifiex_adapter *, struct sk_buff *);
        int (*dnld_fw) (struct mwifiex_adapter *, struct mwifiex_fw_image *);
+       void (*card_reset) (struct mwifiex_adapter *);
 };
 
 struct mwifiex_adapter {
@@ -788,7 +789,7 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
                       struct mwifiex_tx_param *tx_param);
 int mwifiex_send_null_packet(struct mwifiex_private *priv, u8 flags);
 int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
-                               struct sk_buff *skb, int status);
+                               struct sk_buff *skb, int aggr, int status);
 void mwifiex_clean_txrx(struct mwifiex_private *priv);
 u8 mwifiex_check_last_packet_indication(struct mwifiex_private *priv);
 void mwifiex_check_ps_cond(struct mwifiex_adapter *adapter);
@@ -1016,7 +1017,6 @@ int mwifiex_get_ver_ext(struct mwifiex_private *priv);
 
 int mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
                               struct ieee80211_channel *chan,
-                              enum nl80211_channel_type *channel_type,
                               unsigned int duration);
 
 int mwifiex_set_bss_role(struct mwifiex_private *priv, u8 bss_role);
index 82cf0fa2d9f683a391bb2215f94447d53d09ef40..5a1c1d0e5599ab2689b8fee3d1e81d796dead8fc 100644 (file)
@@ -906,8 +906,8 @@ static void mwifiex_interrupt_status(struct mwifiex_adapter *adapter)
 /*
  * SDIO interrupt handler.
  *
- * This function reads the interrupt status from firmware and assigns
- * the main process in workqueue which will handle the interrupt.
+ * This function reads the interrupt status from firmware and handles
+ * the interrupt in current thread (ksdioirqd) right away.
  */
 static void
 mwifiex_sdio_interrupt(struct sdio_func *func)
@@ -930,7 +930,7 @@ mwifiex_sdio_interrupt(struct sdio_func *func)
                adapter->ps_state = PS_STATE_AWAKE;
 
        mwifiex_interrupt_status(adapter);
-       queue_work(adapter->workqueue, &adapter->main_work);
+       mwifiex_main_process(adapter);
 }
 
 /*
@@ -1749,6 +1749,37 @@ mwifiex_update_mp_end_port(struct mwifiex_adapter *adapter, u16 port)
                port, card->mp_data_port_mask);
 }
 
+static struct mmc_host *reset_host;
+static void sdio_card_reset_worker(struct work_struct *work)
+{
+       /* The actual reset operation must be run outside of driver thread.
+        * This is because mmc_remove_host() will cause the device to be
+        * instantly destroyed, and the driver then needs to end its thread,
+        * leading to a deadlock.
+        *
+        * We run it in a totally independent workqueue.
+        */
+
+       pr_err("Resetting card...\n");
+       mmc_remove_host(reset_host);
+       /* 20ms delay is based on experiment with sdhci controller */
+       mdelay(20);
+       mmc_add_host(reset_host);
+}
+static DECLARE_WORK(card_reset_work, sdio_card_reset_worker);
+
+/* This function resets the card */
+static void mwifiex_sdio_card_reset(struct mwifiex_adapter *adapter)
+{
+       struct sdio_mmc_card *card = adapter->card;
+
+       if (work_pending(&card_reset_work))
+               return;
+
+       reset_host = card->func->card->host;
+       schedule_work(&card_reset_work);
+}
+
 static struct mwifiex_if_ops sdio_ops = {
        .init_if = mwifiex_init_sdio,
        .cleanup_if = mwifiex_cleanup_sdio,
@@ -1767,6 +1798,7 @@ static struct mwifiex_if_ops sdio_ops = {
        .cleanup_mpa_buf = mwifiex_cleanup_mpa_buf,
        .cmdrsp_complete = mwifiex_sdio_cmdrsp_complete,
        .event_complete = mwifiex_sdio_event_complete,
+       .card_reset = mwifiex_sdio_card_reset,
 };
 
 /*
@@ -1804,6 +1836,7 @@ mwifiex_sdio_cleanup_module(void)
        /* Set the flag as user is removing this module. */
        user_rmmod = 1;
 
+       cancel_work_sync(&card_reset_work);
        sdio_unregister_driver(&mwifiex_sdio);
 }
 
index 21033738ef0c664d7c00bcf1babc2eece48832c0..8cc5468654b401f2b116c8963859f1712b299cb4 100644 (file)
@@ -25,6 +25,7 @@
 #include <linux/mmc/sdio_ids.h>
 #include <linux/mmc/sdio_func.h>
 #include <linux/mmc/card.h>
+#include <linux/mmc/host.h>
 
 #include "main.h"
 
index 8132119e1a211a41c887a0bda77f433af41a8bcd..41aafc7454ed2b626bded2d96d9f8f9ac143a992 100644 (file)
@@ -124,8 +124,7 @@ mwifiex_reset_connect_state(struct mwifiex_private *priv, u16 reason_code)
        }
        memset(priv->cfg_bssid, 0, ETH_ALEN);
 
-       if (!netif_queue_stopped(priv->netdev))
-               mwifiex_stop_net_dev_queue(priv->netdev, adapter);
+       mwifiex_stop_net_dev_queue(priv->netdev, adapter);
        if (netif_carrier_ok(priv->netdev))
                netif_carrier_off(priv->netdev);
 }
@@ -197,8 +196,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                dev_dbg(adapter->dev, "event: LINK_SENSED\n");
                if (!netif_carrier_ok(priv->netdev))
                        netif_carrier_on(priv->netdev);
-               if (netif_queue_stopped(priv->netdev))
-                       mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
+               mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
                break;
 
        case EVENT_DEAUTHENTICATED:
@@ -306,8 +304,7 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                dev_dbg(adapter->dev, "event: ADHOC_BCN_LOST\n");
                priv->adhoc_is_link_sensed = false;
                mwifiex_clean_txrx(priv);
-               if (!netif_queue_stopped(priv->netdev))
-                       mwifiex_stop_net_dev_queue(priv->netdev, adapter);
+               mwifiex_stop_net_dev_queue(priv->netdev, adapter);
                if (netif_carrier_ok(priv->netdev))
                        netif_carrier_off(priv->netdev);
                break;
@@ -424,7 +421,6 @@ int mwifiex_process_sta_event(struct mwifiex_private *priv)
                cfg80211_remain_on_channel_expired(priv->wdev,
                                                   priv->roc_cfg.cookie,
                                                   &priv->roc_cfg.chan,
-                                                  priv->roc_cfg.chan_type,
                                                   GFP_ATOMIC);
 
                memset(&priv->roc_cfg, 0x00, sizeof(struct mwifiex_roc_cfg));
index 552d72ed055aa63e96c5d01b0cdeadabed646f98..237c8d2ba9f277f0a69677c9b2df3d8e2a4fed43 100644 (file)
@@ -276,8 +276,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
                dev_dbg(adapter->dev, "info: SSID found in scan list ... "
                                      "associating...\n");
 
-               if (!netif_queue_stopped(priv->netdev))
-                       mwifiex_stop_net_dev_queue(priv->netdev, adapter);
+               mwifiex_stop_net_dev_queue(priv->netdev, adapter);
                if (netif_carrier_ok(priv->netdev))
                        netif_carrier_off(priv->netdev);
 
@@ -318,8 +317,7 @@ int mwifiex_bss_start(struct mwifiex_private *priv, struct cfg80211_bss *bss,
 
                ret = mwifiex_check_network_compatibility(priv, bss_desc);
 
-               if (!netif_queue_stopped(priv->netdev))
-                       mwifiex_stop_net_dev_queue(priv->netdev, adapter);
+               mwifiex_stop_net_dev_queue(priv->netdev, adapter);
                if (netif_carrier_ok(priv->netdev))
                        netif_carrier_off(priv->netdev);
 
@@ -1046,7 +1044,6 @@ mwifiex_get_ver_ext(struct mwifiex_private *priv)
 int
 mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
                           struct ieee80211_channel *chan,
-                          enum nl80211_channel_type *ct,
                           unsigned int duration)
 {
        struct host_cmd_ds_remain_on_chan roc_cfg;
@@ -1056,7 +1053,7 @@ mwifiex_remain_on_chan_cfg(struct mwifiex_private *priv, u16 action,
        roc_cfg.action = cpu_to_le16(action);
        if (action == HostCmd_ACT_GEN_SET) {
                roc_cfg.band_cfg = chan->band;
-               sc = mwifiex_chan_type_to_sec_chan_offset(*ct);
+               sc = mwifiex_chan_type_to_sec_chan_offset(NL80211_CHAN_NO_HT);
                roc_cfg.band_cfg |= (sc << 2);
 
                roc_cfg.channel =
index 5cb3f7af87491a1cd7bd39d600f336dbd09b74d6..8c80024c30ff6345399d53e7132bed310a6c12a6 100644 (file)
@@ -121,13 +121,13 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
                dev_err(adapter->dev, "mwifiex_write_data_async failed: 0x%X\n",
                        ret);
                adapter->dbg.num_tx_host_to_card_failure++;
-               mwifiex_write_data_complete(adapter, skb, ret);
+               mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        case -EINPROGRESS:
                adapter->data_sent = false;
                break;
        case 0:
-               mwifiex_write_data_complete(adapter, skb, ret);
+               mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        default:
                break;
@@ -144,11 +144,12 @@ int mwifiex_process_tx(struct mwifiex_private *priv, struct sk_buff *skb,
  * wakes up stalled traffic queue if required, and then frees the buffer.
  */
 int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
-                               struct sk_buff *skb, int status)
+                               struct sk_buff *skb, int aggr, int status)
 {
-       struct mwifiex_private *priv, *tpriv;
+       struct mwifiex_private *priv;
        struct mwifiex_txinfo *tx_info;
-       int i;
+       struct netdev_queue *txq;
+       int index;
 
        if (!skb)
                return 0;
@@ -172,15 +173,20 @@ int mwifiex_write_data_complete(struct mwifiex_adapter *adapter,
 
        if (tx_info->flags & MWIFIEX_BUF_FLAG_BRIDGED_PKT)
                atomic_dec_return(&adapter->pending_bridged_pkts);
-       if (atomic_dec_return(&adapter->tx_pending) >= LOW_TX_PENDING)
+
+       if (aggr)
+               /* For skb_aggr, do not wake up tx queue */
                goto done;
 
-       for (i = 0; i < adapter->priv_num; i++) {
-               tpriv = adapter->priv[i];
+       atomic_dec(&adapter->tx_pending);
 
-               if (tpriv->media_connected &&
-                   netif_queue_stopped(tpriv->netdev))
-                       mwifiex_wake_up_net_dev_queue(tpriv->netdev, adapter);
+       index = mwifiex_1d_to_wmm_queue[skb->priority];
+       if (atomic_dec_return(&priv->wmm_tx_pending[index]) < LOW_TX_PENDING) {
+               txq = netdev_get_tx_queue(priv->netdev, index);
+               if (netif_tx_queue_stopped(txq)) {
+                       netif_tx_wake_queue(txq);
+                       dev_dbg(adapter->dev, "wake queue: %d\n", index);
+               }
        }
 done:
        dev_kfree_skb_any(skb);
index a33fa394e3499cbca7e03b413c00f9afd42e772e..21c640d3b57919792e53406ed94ae7cca96a90e7 100644 (file)
@@ -235,11 +235,18 @@ int mwifiex_process_uap_event(struct mwifiex_private *priv)
                break;
        case EVENT_UAP_BSS_IDLE:
                priv->media_connected = false;
+               if (netif_carrier_ok(priv->netdev))
+                       netif_carrier_off(priv->netdev);
+               mwifiex_stop_net_dev_queue(priv->netdev, adapter);
+
                mwifiex_clean_txrx(priv);
                mwifiex_del_all_sta_list(priv);
                break;
        case EVENT_UAP_BSS_ACTIVE:
                priv->media_connected = true;
+               if (!netif_carrier_ok(priv->netdev))
+                       netif_carrier_on(priv->netdev);
+               mwifiex_wake_up_net_dev_queue(priv->netdev, adapter);
                break;
        case EVENT_UAP_BSS_START:
                dev_dbg(adapter->dev, "AP EVENT: event id: %#x\n", eventcause);
index 22a5916564b84099576e1c554b37d1fcbcd420b2..bbe1f3518e4b4a9fd7b578936845be8da8a45d4d 100644 (file)
@@ -238,7 +238,7 @@ static void mwifiex_usb_tx_complete(struct urb *urb)
        } else {
                dev_dbg(adapter->dev, "%s: DATA\n", __func__);
                atomic_dec(&card->tx_data_urb_pending);
-               mwifiex_write_data_complete(adapter, context->skb,
+               mwifiex_write_data_complete(adapter, context->skb, 0,
                                            urb->status ? -1 : 0);
        }
 
index 600d8194610e3b0c3c7d6c87a0400a5b290514a4..818f871ae987fc4944741562e18fca47b2fdd156 100644 (file)
@@ -483,7 +483,7 @@ mwifiex_wmm_del_pkts_in_ralist_node(struct mwifiex_private *priv,
        struct sk_buff *skb, *tmp;
 
        skb_queue_walk_safe(&ra_list->skb_head, skb, tmp)
-               mwifiex_write_data_complete(adapter, skb, -1);
+               mwifiex_write_data_complete(adapter, skb, 0, -1);
 }
 
 /*
@@ -650,7 +650,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
 
        if (!priv->media_connected && !mwifiex_is_skb_mgmt_frame(skb)) {
                dev_dbg(adapter->dev, "data: drop packet in disconnect\n");
-               mwifiex_write_data_complete(adapter, skb, -1);
+               mwifiex_write_data_complete(adapter, skb, 0, -1);
                return;
        }
 
@@ -680,7 +680,7 @@ mwifiex_wmm_add_buf_txqueue(struct mwifiex_private *priv,
 
        if (!ra_list) {
                spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock, flags);
-               mwifiex_write_data_complete(adapter, skb, -1);
+               mwifiex_write_data_complete(adapter, skb, 0, -1);
                return;
        }
 
@@ -1090,7 +1090,7 @@ mwifiex_send_single_packet(struct mwifiex_private *priv,
                if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
                        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                               ra_list_flags);
-                       mwifiex_write_data_complete(adapter, skb, -1);
+                       mwifiex_write_data_complete(adapter, skb, 0, -1);
                        return;
                }
 
@@ -1195,7 +1195,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
                if (!mwifiex_is_ralist_valid(priv, ptr, ptr_index)) {
                        spin_unlock_irqrestore(&priv->wmm.ra_list_spinlock,
                                               ra_list_flags);
-                       mwifiex_write_data_complete(adapter, skb, -1);
+                       mwifiex_write_data_complete(adapter, skb, 0, -1);
                        return;
                }
 
@@ -1209,7 +1209,7 @@ mwifiex_send_processed_packet(struct mwifiex_private *priv,
                adapter->data_sent = false;
                dev_err(adapter->dev, "host_to_card failed: %#x\n", ret);
                adapter->dbg.num_tx_host_to_card_failure++;
-               mwifiex_write_data_complete(adapter, skb, ret);
+               mwifiex_write_data_complete(adapter, skb, 0, ret);
                break;
        case -EINPROGRESS:
                adapter->data_sent = false;
index ec839952d2e77bc01bf57bb63be53086913821f0..b92f39d8963beeaeca0f14800e4a0c06081c893a 100644 (file)
@@ -31,6 +31,8 @@ enum ieee_types_wmm_ecw_bitmasks {
        MWIFIEX_ECW_MAX = (BIT(4) | BIT(5) | BIT(6) | BIT(7)),
 };
 
+static const u16 mwifiex_1d_to_wmm_queue[8] = { 1, 0, 0, 1, 2, 2, 3, 3 };
+
 /*
  * This function retrieves the TID of the given RA list.
  */
index 5099e5375cb39ed8e22a7382f6a42bc939c47fb7..0cdae663273554c91ecab874ed1d46d728d8d533 100644 (file)
@@ -1851,6 +1851,7 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
        bool start_ba_session = false;
        bool mgmtframe = false;
        struct ieee80211_mgmt *mgmt = (struct ieee80211_mgmt *)skb->data;
+       bool eapol_frame = false;
 
        wh = (struct ieee80211_hdr *)skb->data;
        if (ieee80211_is_data_qos(wh->frame_control))
@@ -1858,6 +1859,9 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
        else
                qos = 0;
 
+       if (skb->protocol == cpu_to_be16(ETH_P_PAE))
+               eapol_frame = true;
+
        if (ieee80211_is_mgmt(wh->frame_control))
                mgmtframe = true;
 
@@ -1916,9 +1920,8 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
 
        txpriority = index;
 
-       if (priv->ap_fw && sta && sta->ht_cap.ht_supported
-                       && skb->protocol != cpu_to_be16(ETH_P_PAE)
-                       && ieee80211_is_data_qos(wh->frame_control)) {
+       if (priv->ap_fw && sta && sta->ht_cap.ht_supported && !eapol_frame &&
+           ieee80211_is_data_qos(wh->frame_control)) {
                tid = qos & 0xf;
                mwl8k_tx_count_packet(sta, tid);
                spin_lock(&priv->stream_lock);
@@ -2005,6 +2008,8 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
                                spin_unlock(&priv->stream_lock);
                        }
                        spin_unlock_bh(&priv->tx_lock);
+                       pci_unmap_single(priv->pdev, dma, skb->len,
+                                        PCI_DMA_TODEVICE);
                        dev_kfree_skb(skb);
                        return;
                }
@@ -2025,9 +2030,11 @@ mwl8k_txq_xmit(struct ieee80211_hw *hw,
        else
                tx->peer_id = 0;
 
-       if (priv->ap_fw)
+       if (priv->ap_fw && ieee80211_is_data(wh->frame_control) && !eapol_frame)
                tx->timestamp = cpu_to_le32(ioread32(priv->regs +
                                                MWL8K_HW_TIMER_REGISTER));
+       else
+               tx->timestamp = 0;
 
        wmb();
        tx->status = cpu_to_le32(MWL8K_TXD_STATUS_FW_OWNED | txstatus);
@@ -3679,7 +3686,8 @@ struct mwl8k_cmd_bastream {
 } __packed;
 
 static int
-mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
+mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream,
+              struct ieee80211_vif *vif)
 {
        struct mwl8k_cmd_bastream *cmd;
        int rc;
@@ -3702,7 +3710,7 @@ mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
                cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE) |
                cpu_to_le32(BASTREAM_FLAG_DIRECTION_UPSTREAM);
 
-       rc = mwl8k_post_cmd(hw, &cmd->header);
+       rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
 
        kfree(cmd);
 
@@ -3711,7 +3719,7 @@ mwl8k_check_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream)
 
 static int
 mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream,
-               u8 buf_size)
+               u8 buf_size, struct ieee80211_vif *vif)
 {
        struct mwl8k_cmd_bastream *cmd;
        int rc;
@@ -3745,7 +3753,7 @@ mwl8k_create_ba(struct ieee80211_hw *hw, struct mwl8k_ampdu_stream *stream,
                cpu_to_le32(BASTREAM_FLAG_IMMEDIATE_TYPE |
                                        BASTREAM_FLAG_DIRECTION_UPSTREAM);
 
-       rc = mwl8k_post_cmd(hw, &cmd->header);
+       rc = mwl8k_post_pervif_cmd(hw, vif, &cmd->header);
 
        wiphy_debug(hw->wiphy, "Created a BA stream for %pM : tid %d\n",
                stream->sta->addr, stream->tid);
@@ -5085,6 +5093,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
        struct mwl8k_priv *priv = hw->priv;
        struct mwl8k_ampdu_stream *stream;
        u8 *addr = sta->addr;
+       struct mwl8k_sta *sta_info = MWL8K_STA(sta);
 
        if (!(hw->flags & IEEE80211_HW_AMPDU_AGGREGATION))
                return -ENOTSUPP;
@@ -5127,7 +5136,16 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                /* Release the lock before we do the time consuming stuff */
                spin_unlock(&priv->stream_lock);
                for (i = 0; i < MAX_AMPDU_ATTEMPTS; i++) {
-                       rc = mwl8k_check_ba(hw, stream);
+
+                       /* Check if link is still valid */
+                       if (!sta_info->is_ampdu_allowed) {
+                               spin_lock(&priv->stream_lock);
+                               mwl8k_remove_stream(hw, stream);
+                               spin_unlock(&priv->stream_lock);
+                               return -EBUSY;
+                       }
+
+                       rc = mwl8k_check_ba(hw, stream, vif);
 
                        /* If HW restart is in progress mwl8k_post_cmd will
                         * return -EBUSY. Avoid retrying mwl8k_check_ba in
@@ -5167,7 +5185,7 @@ mwl8k_ampdu_action(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                BUG_ON(stream == NULL);
                BUG_ON(stream->state != AMPDU_STREAM_IN_PROGRESS);
                spin_unlock(&priv->stream_lock);
-               rc = mwl8k_create_ba(hw, stream, buf_size);
+               rc = mwl8k_create_ba(hw, stream, buf_size, vif);
                spin_lock(&priv->stream_lock);
                if (!rc)
                        stream->state = AMPDU_STREAM_ACTIVE;
@@ -5617,6 +5635,18 @@ fail:
        return rc;
 }
 
+static const struct ieee80211_iface_limit ap_if_limits[] = {
+       { .max = 8,     .types = BIT(NL80211_IFTYPE_AP) },
+};
+
+static const struct ieee80211_iface_combination ap_if_comb = {
+       .limits = ap_if_limits,
+       .n_limits = ARRAY_SIZE(ap_if_limits),
+       .max_interfaces = 8,
+       .num_different_channels = 1,
+};
+
+
 static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
 {
        struct ieee80211_hw *hw = priv->hw;
@@ -5696,8 +5726,13 @@ static int mwl8k_firmware_load_success(struct mwl8k_priv *priv)
                goto err_free_cookie;
 
        hw->wiphy->interface_modes = 0;
-       if (priv->ap_macids_supported || priv->device_info->fw_image_ap)
+
+       if (priv->ap_macids_supported || priv->device_info->fw_image_ap) {
                hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_AP);
+               hw->wiphy->iface_combinations = &ap_if_comb;
+               hw->wiphy->n_iface_combinations = 1;
+       }
+
        if (priv->sta_macids_supported || priv->device_info->fw_image_sta)
                hw->wiphy->interface_modes |= BIT(NL80211_IFTYPE_STATION);
 
index 7b751fba7e1f90176d797ab1a2bc88ce72e5f6ac..d01edd2c50c505866cb554826659e24b4489c68f 100644 (file)
@@ -161,24 +161,23 @@ static int orinoco_scan(struct wiphy *wiphy,
 }
 
 static int orinoco_set_monitor_channel(struct wiphy *wiphy,
-                                      struct ieee80211_channel *chan,
-                                      enum nl80211_channel_type channel_type)
+                                      struct cfg80211_chan_def *chandef)
 {
        struct orinoco_private *priv = wiphy_priv(wiphy);
        int err = 0;
        unsigned long flags;
        int channel;
 
-       if (!chan)
+       if (!chandef->chan)
                return -EINVAL;
 
-       if (channel_type != NL80211_CHAN_NO_HT)
+       if (cfg80211_get_chandef_type(chandef) != NL80211_CHAN_NO_HT)
                return -EINVAL;
 
-       if (chan->band != IEEE80211_BAND_2GHZ)
+       if (chandef->chan->band != IEEE80211_BAND_2GHZ)
                return -EINVAL;
 
-       channel = ieee80211_freq_to_dsss_chan(chan->center_freq);
+       channel = ieee80211_freq_to_dsss_chan(chandef->chan->center_freq);
 
        if ((channel < 1) || (channel > NUM_CHANNELS) ||
             !(priv->channel_mask & (1 << (channel - 1))))
index 5861e13a6fd8d5f9aa83c24892acfc11a210b02e..12f0a34477f231cff73a591f3bc5a2af300ce9d0 100644 (file)
@@ -369,7 +369,11 @@ static int p54_rx_data(struct p54_common *priv, struct sk_buff *skb)
        rx_status->mactime = ((u64)priv->tsf_high32) << 32 | tsf32;
        priv->tsf_low32 = tsf32;
 
-       rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+       /* LMAC API Page 10/29 - s_lm_data_in - clock
+        * "usec accurate timestamp of hardware clock
+        * at end of frame (before OFDM SIFS EOF padding"
+        */
+       rx_status->flag |= RX_FLAG_MACTIME_END;
 
        if (hdr->flags & cpu_to_le16(P54_HDR_FLAG_DATA_ALIGN))
                header_len += hdr->align[0];
index bd1f0cb56085ef94eb5e634a7467f1c12e3a3ffb..abe1d039be814150d1815949e90f78b38573fa2d 100644 (file)
@@ -490,9 +490,12 @@ static int rndis_scan(struct wiphy *wiphy,
 static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed);
 
 static int rndis_set_tx_power(struct wiphy *wiphy,
+                             struct wireless_dev *wdev,
                              enum nl80211_tx_power_setting type,
                              int mbm);
-static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm);
+static int rndis_get_tx_power(struct wiphy *wiphy,
+                             struct wireless_dev *wdev,
+                             int *dbm);
 
 static int rndis_connect(struct wiphy *wiphy, struct net_device *dev,
                                struct cfg80211_connect_params *sme);
@@ -1903,6 +1906,7 @@ static int rndis_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 }
 
 static int rndis_set_tx_power(struct wiphy *wiphy,
+                             struct wireless_dev *wdev,
                              enum nl80211_tx_power_setting type,
                              int mbm)
 {
@@ -1930,7 +1934,9 @@ static int rndis_set_tx_power(struct wiphy *wiphy,
        return -ENOTSUPP;
 }
 
-static int rndis_get_tx_power(struct wiphy *wiphy, int *dbm)
+static int rndis_get_tx_power(struct wiphy *wiphy,
+                             struct wireless_dev *wdev,
+                             int *dbm)
 {
        struct rndis_wlan_private *priv = wiphy_priv(wiphy);
        struct usbnet *usbdev = priv->usbdev;
@@ -2287,7 +2293,7 @@ static int rndis_join_ibss(struct wiphy *wiphy, struct net_device *dev,
 {
        struct rndis_wlan_private *priv = wiphy_priv(wiphy);
        struct usbnet *usbdev = priv->usbdev;
-       struct ieee80211_channel *channel = params->channel;
+       struct ieee80211_channel *channel = params->chandef.chan;
        struct ndis_80211_ssid ssid;
        enum nl80211_auth_type auth_type;
        int ret, alg, length, chan = -1;
index 3b8fb5a603f25244241a3219bff169962cf54733..023081286e0c3a0490f4d2228ec85ba7cd618703 100644 (file)
@@ -1096,6 +1096,7 @@ static struct usb_device_id rt2800usb_device_table[] = {
        { USB_DEVICE(0x177f, 0x0153) },
        { USB_DEVICE(0x177f, 0x0302) },
        { USB_DEVICE(0x177f, 0x0313) },
+       { USB_DEVICE(0x177f, 0x0323) },
        /* U-Media */
        { USB_DEVICE(0x157e, 0x300e) },
        { USB_DEVICE(0x157e, 0x3013) },
index 69097d1faeb676d97ddd27c7ba7dc3f575cd2f6f..67d167993d4590237c4850ccfd3d2717ce739536 100644 (file)
@@ -157,6 +157,7 @@ static void rt2x00lib_intf_scheduled(struct work_struct *work)
         * requested configurations.
         */
        ieee80211_iterate_active_interfaces(rt2x00dev->hw,
+                                           IEEE80211_IFACE_ITER_RESUME_ALL,
                                            rt2x00lib_intf_scheduled_iter,
                                            rt2x00dev);
 }
@@ -225,9 +226,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
                return;
 
        /* send buffered bc/mc frames out for every bssid */
-       ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
-                                                  rt2x00lib_bc_buffer_iter,
-                                                  rt2x00dev);
+       ieee80211_iterate_active_interfaces_atomic(
+               rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               rt2x00lib_bc_buffer_iter, rt2x00dev);
        /*
         * Devices with pre tbtt interrupt don't need to update the beacon
         * here as they will fetch the next beacon directly prior to
@@ -237,9 +238,9 @@ void rt2x00lib_beacondone(struct rt2x00_dev *rt2x00dev)
                return;
 
        /* fetch next beacon */
-       ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
-                                                  rt2x00lib_beaconupdate_iter,
-                                                  rt2x00dev);
+       ieee80211_iterate_active_interfaces_atomic(
+               rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               rt2x00lib_beaconupdate_iter, rt2x00dev);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_beacondone);
 
@@ -249,9 +250,9 @@ void rt2x00lib_pretbtt(struct rt2x00_dev *rt2x00dev)
                return;
 
        /* fetch next beacon */
-       ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
-                                                  rt2x00lib_beaconupdate_iter,
-                                                  rt2x00dev);
+       ieee80211_iterate_active_interfaces_atomic(
+               rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               rt2x00lib_beaconupdate_iter, rt2x00dev);
 }
 EXPORT_SYMBOL_GPL(rt2x00lib_pretbtt);
 
index 98a9e48f8e4a38e852c54e8dbdef0c2369a753a4..ed7a1bb3f2450223e780e344e014efa51d290dbb 100644 (file)
@@ -424,9 +424,9 @@ int rt2x00mac_set_tim(struct ieee80211_hw *hw, struct ieee80211_sta *sta,
        if (!test_bit(DEVICE_STATE_ENABLED_RADIO, &rt2x00dev->flags))
                return 0;
 
-       ieee80211_iterate_active_interfaces_atomic(rt2x00dev->hw,
-                                                  rt2x00mac_set_tim_iter,
-                                                  rt2x00dev);
+       ieee80211_iterate_active_interfaces_atomic(
+               rt2x00dev->hw, IEEE80211_IFACE_ITER_RESUME_ALL,
+               rt2x00mac_set_tim_iter, rt2x00dev);
 
        /* queue work to upodate the beacon template */
        ieee80211_queue_work(rt2x00dev->hw, &rt2x00dev->intf_work);
index 021d83e1b1d3367d0ff19954324c4306dc6b8f42..b4218a5f20663ace7ece31051674090af4b20325 100644 (file)
@@ -150,7 +150,7 @@ static void rtl8180_handle_rx(struct ieee80211_hw *dev)
                        rx_status.freq = dev->conf.channel->center_freq;
                        rx_status.band = dev->conf.channel->band;
                        rx_status.mactime = le64_to_cpu(entry->tsft);
-                       rx_status.flag |= RX_FLAG_MACTIME_MPDU;
+                       rx_status.flag |= RX_FLAG_MACTIME_START;
                        if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
                                rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
 
index 7811b6315973cd466e19d2fd2c139532daf04610..52e6bebcf089460390a291c8937048205f0493f6 100644 (file)
@@ -381,7 +381,7 @@ static void rtl8187_rx_cb(struct urb *urb)
        rx_status.rate_idx = rate;
        rx_status.freq = dev->conf.channel->center_freq;
        rx_status.band = dev->conf.channel->band;
-       rx_status.flag |= RX_FLAG_MACTIME_MPDU;
+       rx_status.flag |= RX_FLAG_MACTIME_START;
        if (flags & RTL818X_RX_DESC_FLAG_CRC32_ERR)
                rx_status.flag |= RX_FLAG_FAILED_FCS_CRC;
        memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
index 6b28e92d1d215c0f598354326b9c1e9780376268..21b1bbb93a7e41452720a6f9ede17cba3951393e 100644 (file)
@@ -32,6 +32,17 @@ config RTL8192DE
 
        If you choose to build it as a module, it will be called rtl8192de
 
+config RTL8723AE
+       tristate "Realtek RTL8723AE PCIe Wireless Network Adapter"
+       depends on MAC80211 && PCI && EXPERIMENTAL
+       select FW_LOADER
+       select RTLWIFI
+       ---help---
+       This is the driver for Realtek RTL8723AE 802.11n PCIe
+       wireless network adapters.
+
+       If you choose to build it as a module, it will be called rtl8723ae
+
 config RTL8192CU
        tristate "Realtek RTL8192CU/RTL8188CU USB Wireless Network Adapter"
        depends on MAC80211 && USB
index 97935c565babd456952ffc2ac9ffbe1a89891402..3b1cbac741e3f4b91c41dd5c0360cb5fe521b88a 100644 (file)
@@ -7,7 +7,8 @@ rtlwifi-objs    :=              \
                efuse.o         \
                ps.o            \
                rc.o            \
-               regd.o
+               regd.o          \
+               stats.o
 
 rtl8192c_common-objs +=                \
 
@@ -24,5 +25,6 @@ obj-$(CONFIG_RTL8192CE)               += rtl8192ce/
 obj-$(CONFIG_RTL8192CU)                += rtl8192cu/
 obj-$(CONFIG_RTL8192SE)                += rtl8192se/
 obj-$(CONFIG_RTL8192DE)                += rtl8192de/
+obj-$(CONFIG_RTL8723AE)                += rtl8723ae/
 
 ccflags-y += -D__CHECK_ENDIAN__
index 59381fe8ed064064dcddaf697ba26aa345b2c0de..4494d130b37cb0d0ad585eea5142e0c312c86b26 100644 (file)
@@ -826,6 +826,30 @@ int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
 }
 EXPORT_SYMBOL(rtlwifi_rate_mapping);
 
+bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       __le16 fc = rtl_get_fc(skb);
+
+       if (rtlpriv->dm.supp_phymode_switch &&
+           mac->link_state < MAC80211_LINKED &&
+           (ieee80211_is_auth(fc) || ieee80211_is_probe_req(fc))) {
+               if (rtlpriv->cfg->ops->check_switch_to_dmdp)
+                       rtlpriv->cfg->ops->check_switch_to_dmdp(hw);
+       }
+       if (ieee80211_is_auth(fc)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
+               rtl_ips_nic_on(hw);
+
+               mac->link_state = MAC80211_LINKING;
+               /* Dual mac */
+               rtlpriv->phy.need_iqk = true;
+       }
+
+       return true;
+}
+
 void rtl_get_tcb_desc(struct ieee80211_hw *hw,
                      struct ieee80211_tx_info *info,
                      struct ieee80211_sta *sta,
index f35af0fdaaf0ae8dc9a44a26a51d6f3480126a1c..5a8c80e259f7f36070f05b096e4187064f829729 100644 (file)
@@ -142,4 +142,6 @@ u8 rtl_tid_to_ac(u8 tid);
 extern struct attribute_group rtl_attribute_group;
 int rtlwifi_rate_mapping(struct ieee80211_hw *hw,
                         bool isht, u8 desc_rate, bool first_ampdu);
+bool rtl_tx_mgmt_proc(struct ieee80211_hw *hw, struct sk_buff *skb);
+
 #endif
index ca69e35e50f126582ae73b2b9a35f96a8a075469..0e510f73041ab88659b131c2a392598046e127fe 100644 (file)
@@ -337,7 +337,7 @@ void rtl_cam_del_entry(struct ieee80211_hw *hw, u8 *sta_addr)
                if (((bitmap & BIT(0)) == BIT(0)) &&
                    (memcmp(addr, sta_addr, ETH_ALEN) == 0)) {
                        /* Remove from HW Security CAM */
-                       memset(rtlpriv->sec.hwsec_cam_sta_addr[i], 0, ETH_ALEN);
+                       eth_zero_addr(rtlpriv->sec.hwsec_cam_sta_addr[i]);
                        rtlpriv->sec.hwsec_cam_bitmap &= ~(BIT(0) << i);
                        RT_TRACE(rtlpriv, COMP_SEC, DBG_LOUD,
                                 "del CAM entry %d\n", i);
index a7c0e52869ba3c708cf39685c59489122353b4a0..be33aa14c8afaa6672497d156abebb4b3cd146f9 100644 (file)
@@ -962,7 +962,6 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
        int err = 0;
        u8 mac_addr[ETH_ALEN];
        u8 bcast_addr[ETH_ALEN] = { 0xff, 0xff, 0xff, 0xff, 0xff, 0xff };
-       u8 zero_addr[ETH_ALEN] = { 0 };
 
        if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
@@ -1057,7 +1056,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                        memcpy(rtlpriv->sec.key_buf[key_idx],
                               key->key, key->keylen);
                        rtlpriv->sec.key_len[key_idx] = key->keylen;
-                       memcpy(mac_addr, zero_addr, ETH_ALEN);
+                       eth_zero_addr(mac_addr);
                } else if (group_key) { /* group key */
                        RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
                                 "set group key\n");
@@ -1108,7 +1107,7 @@ static int rtl_op_set_key(struct ieee80211_hw *hw, enum set_key_cmd cmd,
                }
                memset(rtlpriv->sec.key_buf[key_idx], 0, key->keylen);
                rtlpriv->sec.key_len[key_idx] = 0;
-               memcpy(mac_addr, zero_addr, ETH_ALEN);
+               eth_zero_addr(mac_addr);
                /*
                 *mac80211 will delete entrys one by one,
                 *so don't use rtl_cam_reset_all_entry
index 07493d2957f2a11d313275643b1fee0bc7c6196f..fd3269f476854235993dbcf04990fcab6d43b810 100644 (file)
 #define COMP_REGD                      BIT(27)
 #define COMP_CHAN                      BIT(28)
 #define COMP_USB                       BIT(29)
+#define COMP_EASY_CONCURRENT   COMP_USB /* reuse of this bit is OK */
+#define COMP_BT_COEXIST                        BIT(30)
 
 /*--------------------------------------------------------------
                Define the rt_print components
index abc306b502ac0348b97dd40eae26c01ebf6947d9..f38e30a947bc9be9f176695d770793b382619393 100644 (file)
@@ -1309,6 +1309,7 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_sta_info *sta_entry = NULL;
        u8 tid = rtl_get_tid(skb);
+       __le16 fc = rtl_get_fc(skb);
 
        if (!sta)
                return false;
@@ -1316,6 +1317,12 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
 
        if (!rtlpriv->rtlhal.earlymode_enable)
                return false;
+       if (ieee80211_is_nullfunc(fc))
+               return false;
+       if (ieee80211_is_qos_nullfunc(fc))
+               return false;
+       if (ieee80211_is_pspoll(fc))
+               return false;
        if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL)
                return false;
        if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE)
@@ -1357,10 +1364,8 @@ static int rtl_pci_tx(struct ieee80211_hw *hw,
        u8 own;
        u8 temp_one = 1;
 
-       if (ieee80211_is_auth(fc)) {
-               RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
-               rtl_ips_nic_on(hw);
-       }
+       if (ieee80211_is_mgmt(fc))
+               rtl_tx_mgmt_proc(hw, skb);
 
        if (rtlpriv->psc.sw_ps_enabled) {
                if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) &&
@@ -1628,7 +1633,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
                                 "8192 PCI-E is found - vid/did=%x/%x\n",
                                 venderid, deviceid);
                        rtlhal->hw_type = HARDWARE_TYPE_RTL8192E;
-                       break;
+                       return false;
                case RTL_PCI_REVISION_ID_8192SE:
                        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
                                 "8192SE is found - vid/did=%x/%x\n",
@@ -1643,6 +1648,11 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
                        break;
 
                }
+       } else if (deviceid == RTL_PCI_8723AE_DID) {
+               rtlhal->hw_type = HARDWARE_TYPE_RTL8723AE;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                        "8723AE PCI-E is found - "
+                        "vid/did=%x/%x\n", venderid, deviceid);
        } else if (deviceid == RTL_PCI_8192CET_DID ||
                   deviceid == RTL_PCI_8192CE_DID ||
                   deviceid == RTL_PCI_8191CE_DID ||
index 241448fc9ed5d190a5a54097571d4f3fc6504870..f71b12aa8cb4c1ea5240f172c53d464242cf60d3 100644 (file)
@@ -79,6 +79,7 @@
 #define RTL_PCI_8173_DID       0x8173  /*8191 SE Crab */
 #define RTL_PCI_8172_DID       0x8172  /*8191 SE RE */
 #define RTL_PCI_8171_DID       0x8171  /*8191 SE Unicron */
+#define RTL_PCI_8723AE_DID     0x8723  /*8723AE */
 #define RTL_PCI_0045_DID       0x0045  /*8190 PCI for Ceraga */
 #define RTL_PCI_0046_DID       0x0046  /*8190 Cardbus for Ceraga */
 #define RTL_PCI_0044_DID       0x0044  /*8192e PCIE for Ceraga */
@@ -152,6 +153,7 @@ struct rtl8192_rx_ring {
 
 struct rtl_pci {
        struct pci_dev *pdev;
+       bool irq_enabled;
 
        bool driver_is_goingto_unload;
        bool up_first_time;
index d5cbf01da8ac0de8a1d04fd2ae7502b67d03ab47..c1e065f136baa631a9245b87f897dea167865431 100644 (file)
@@ -55,7 +55,8 @@ static u8 _rtl_rc_get_highest_rix(struct rtl_priv *rtlpriv,
         *      1M we will not use FW rate but user rate.
         */
        if (rtlmac->opmode == NL80211_IFTYPE_AP ||
-               rtlmac->opmode == NL80211_IFTYPE_ADHOC) {
+           rtlmac->opmode == NL80211_IFTYPE_ADHOC ||
+           rtlmac->opmode == NL80211_IFTYPE_MESH_POINT) {
                if (sta) {
                        sta_entry = (struct rtl_sta_info *) sta->drv_priv;
                        wireless_mode = sta_entry->wireless_mode;
index d7e1f0a7e48f57f4390f93a641175e28138be534..173424756149b95d7d1bc9ea6eb9981fa6603130 100644 (file)
@@ -559,7 +559,7 @@ bool rtl92ce_rx_query_desc(struct ieee80211_hw *hw,
        if (GET_RX_DESC_RXHT(pdesc))
                rx_status->flag |= RX_FLAG_HT;
 
-       rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+       rx_status->flag |= RX_FLAG_MACTIME_START;
 
        if (stats->decrypted)
                rx_status->flag |= RX_FLAG_DECRYPTED;
index 6e66f04c363fb43ad25557e5149cab6a78a6d933..b6222eedb8350c8eb691cfe5fe1fa8eba8b7eaf3 100644 (file)
@@ -334,7 +334,7 @@ bool rtl92cu_rx_query_desc(struct ieee80211_hw *hw,
                rx_status->flag |= RX_FLAG_40MHZ;
        if (GET_RX_DESC_RX_HT(pdesc))
                rx_status->flag |= RX_FLAG_HT;
-       rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+       rx_status->flag |= RX_FLAG_MACTIME_START;
        if (stats->decrypted)
                rx_status->flag |= RX_FLAG_DECRYPTED;
        rx_status->rate_idx = rtlwifi_rate_mapping(hw,
index 35bb9da6196a72417a52709f28151e58aaf0230c..f9f3861046c1f6c4deb0a9454b872ca260618f16 100644 (file)
@@ -509,7 +509,7 @@ bool rtl92de_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
                rx_status->flag |= RX_FLAG_40MHZ;
        if (GET_RX_DESC_RXHT(pdesc))
                rx_status->flag |= RX_FLAG_HT;
-       rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+       rx_status->flag |= RX_FLAG_MACTIME_START;
        if (stats->decrypted)
                rx_status->flag |= RX_FLAG_DECRYPTED;
        rx_status->rate_idx = rtlwifi_rate_mapping(hw,
index 1ad51e711a32c7ffd8a8fb90a5c507a9754d1a9d..0e9f6ebf078add38ded9595f6a454b8182148335 100644 (file)
@@ -553,7 +553,7 @@ bool rtl92se_rx_query_desc(struct ieee80211_hw *hw, struct rtl_stats *stats,
        if (stats->is_ht)
                rx_status->flag |= RX_FLAG_HT;
 
-       rx_status->flag |= RX_FLAG_MACTIME_MPDU;
+       rx_status->flag |= RX_FLAG_MACTIME_START;
 
        /* hw will set stats->decrypted true, if it finds the
         * frame is open data frame or mgmt frame,
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile b/drivers/net/wireless/rtlwifi/rtl8723ae/Makefile
new file mode 100644 (file)
index 0000000..4ed731f
--- /dev/null
@@ -0,0 +1,22 @@
+obj-m := rtl8723ae.o
+
+
+rtl8723ae-objs :=              \
+               dm.o            \
+               fw.o            \
+               hal_btc.o       \
+               hal_bt_coexist.o\
+               hw.o            \
+               led.o           \
+               phy.o           \
+               pwrseq.o        \
+               pwrseqcmd.o     \
+               rf.o            \
+               sw.o            \
+               table.o         \
+               trx.o           \
+
+
+obj-$(CONFIG_RTL8723AE) += rtl8723ae.o
+
+ccflags-y += -D__CHECK_ENDIAN__
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/btc.h b/drivers/net/wireless/rtlwifi/rtl8723ae/btc.h
new file mode 100644 (file)
index 0000000..417afee
--- /dev/null
@@ -0,0 +1,41 @@
+/******************************************************************************
+ **
+ ** Copyright(c) 2009-2012  Realtek Corporation.
+ **
+ ** 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
+ ** published by the Free Software Foundation.
+ **
+ ** This program is distributed in the hope that it will be useful, but WITHOUT
+ ** ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ ** FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ ** more details.
+ **
+ ** You should have received a copy of the GNU General Public License along with
+ ** this program; if not, write to the Free Software Foundation, Inc.,
+ ** 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ **
+ ** The full GNU General Public License is included in this distribution in the
+ ** file called LICENSE.
+ **
+ ** Contact Information:
+ ** wlanfae <wlanfae@realtek.com>
+ ** Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ ** Hsinchu 300, Taiwan.
+ ** Larry Finger <Larry.Finger@lwfinger.net>
+ **
+ *****************************************************************************
+ */
+
+#ifndef __RTL8723E_BTC_H__
+#define __RTL8723E_BTC_H__
+
+#include "../wifi.h"
+#include "hal_bt_coexist.h"
+
+struct bt_coexist_c2h_info {
+       u8 no_parse_c2h;
+       u8 has_c2h;
+};
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/def.h b/drivers/net/wireless/rtlwifi/rtl8723ae/def.h
new file mode 100644 (file)
index 0000000..8c11035
--- /dev/null
@@ -0,0 +1,163 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ****************************************************************************
+ */
+
+#ifndef __RTL8723E_DEF_H__
+#define __RTL8723E_DEF_H__
+
+#define HAL_PRIME_CHNL_OFFSET_LOWER                    1
+
+#define RX_MPDU_QUEUE                                  0
+
+#define CHIP_8723                      BIT(0)
+#define NORMAL_CHIP                    BIT(3)
+#define RF_TYPE_1T2R                   BIT(4)
+#define RF_TYPE_2T2R                   BIT(5)
+#define CHIP_VENDOR_UMC                        BIT(7)
+#define B_CUT_VERSION                  BIT(12)
+#define C_CUT_VERSION                  BIT(13)
+#define D_CUT_VERSION                  ((BIT(12)|BIT(13)))
+#define E_CUT_VERSION                  BIT(14)
+#define        RF_RL_ID                        (BIT(31)|BIT(30)|BIT(29)|BIT(28))
+
+enum version_8723e {
+       VERSION_TEST_UMC_CHIP_8723 = 0x0081,
+       VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT = 0x0089,
+       VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT = 0x1089,
+};
+
+/* MASK */
+#define IC_TYPE_MASK                   (BIT(0)|BIT(1)|BIT(2))
+#define CHIP_TYPE_MASK                 BIT(3)
+#define RF_TYPE_MASK                   (BIT(4)|BIT(5)|BIT(6))
+#define MANUFACTUER_MASK               BIT(7)
+#define ROM_VERSION_MASK               (BIT(11)|BIT(10)|BIT(9)|BIT(8))
+#define CUT_VERSION_MASK               (BIT(15)|BIT(14)|BIT(13)|BIT(12))
+
+/* Get element */
+#define GET_CVID_IC_TYPE(version)      ((version) & IC_TYPE_MASK)
+#define GET_CVID_MANUFACTUER(version)  ((version) & MANUFACTUER_MASK)
+#define GET_CVID_CUT_VERSION(version)  ((version) & CUT_VERSION_MASK)
+
+#define IS_81XXC(version)              ((GET_CVID_IC_TYPE(version) == 0) ?\
+                                       true : false)
+#define IS_8723_SERIES(version)                                                \
+               ((GET_CVID_IC_TYPE(version) == CHIP_8723) ? true : false)
+#define IS_CHIP_VENDOR_UMC(version)                                    \
+               ((GET_CVID_MANUFACTUER(version)) ? true : false)
+
+#define IS_VENDOR_UMC_A_CUT(version)   ((IS_CHIP_VENDOR_UMC(version)) ? \
+               ((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
+#define IS_VENDOR_8723_A_CUT(version)  ((IS_8723_SERIES(version)) ?    \
+               ((GET_CVID_CUT_VERSION(version)) ? false : true) : false)
+#define IS_81xxC_VENDOR_UMC_B_CUT(version)     ((IS_CHIP_VENDOR_UMC(version)) \
+               ? ((GET_CVID_CUT_VERSION(version) == B_CUT_VERSION) ? \
+               true : false) : false)
+
+enum rf_optype {
+       RF_OP_BY_SW_3WIRE = 0,
+       RF_OP_BY_FW,
+       RF_OP_MAX
+};
+
+enum rf_power_state {
+       RF_ON,
+       RF_OFF,
+       RF_SLEEP,
+       RF_SHUT_DOWN,
+};
+
+enum power_save_mode {
+       POWER_SAVE_MODE_ACTIVE,
+       POWER_SAVE_MODE_SAVE,
+};
+
+enum power_polocy_config {
+       POWERCFG_MAX_POWER_SAVINGS,
+       POWERCFG_GLOBAL_POWER_SAVINGS,
+       POWERCFG_LOCAL_POWER_SAVINGS,
+       POWERCFG_LENOVO,
+};
+
+enum interface_select_pci {
+       INTF_SEL1_MINICARD = 0,
+       INTF_SEL0_PCIE = 1,
+       INTF_SEL2_RSV = 2,
+       INTF_SEL3_RSV = 3,
+};
+
+enum hal_fw_c2h_cmd_id {
+       HAL_FW_C2H_CMD_Read_MACREG = 0,
+       HAL_FW_C2H_CMD_Read_BBREG = 1,
+       HAL_FW_C2H_CMD_Read_RFREG = 2,
+       HAL_FW_C2H_CMD_Read_EEPROM = 3,
+       HAL_FW_C2H_CMD_Read_EFUSE = 4,
+       HAL_FW_C2H_CMD_Read_CAM = 5,
+       HAL_FW_C2H_CMD_Get_BasicRate = 6,
+       HAL_FW_C2H_CMD_Get_DataRate = 7,
+       HAL_FW_C2H_CMD_Survey = 8,
+       HAL_FW_C2H_CMD_SurveyDone = 9,
+       HAL_FW_C2H_CMD_JoinBss = 10,
+       HAL_FW_C2H_CMD_AddSTA = 11,
+       HAL_FW_C2H_CMD_DelSTA = 12,
+       HAL_FW_C2H_CMD_AtimDone = 13,
+       HAL_FW_C2H_CMD_TX_Report = 14,
+       HAL_FW_C2H_CMD_CCX_Report = 15,
+       HAL_FW_C2H_CMD_DTM_Report = 16,
+       HAL_FW_C2H_CMD_TX_Rate_Statistics = 17,
+       HAL_FW_C2H_CMD_C2HLBK = 18,
+       HAL_FW_C2H_CMD_C2HDBG = 19,
+       HAL_FW_C2H_CMD_C2HFEEDBACK = 20,
+       HAL_FW_C2H_CMD_MAX
+};
+
+enum rtl_desc_qsel {
+       QSLT_BK = 0x2,
+       QSLT_BE = 0x0,
+       QSLT_VI = 0x5,
+       QSLT_VO = 0x7,
+       QSLT_BEACON = 0x10,
+       QSLT_HIGH = 0x11,
+       QSLT_MGNT = 0x12,
+       QSLT_CMD = 0x13,
+};
+
+struct phy_sts_cck_8723e_t {
+       u8 adc_pwdb_X[4];
+       u8 sq_rpt;
+       u8 cck_agc_rpt;
+};
+
+struct h2c_cmd_8723e {
+       u8 element_id;
+       u32 cmd_len;
+       u8 *p_cmdbuffer;
+};
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.c
new file mode 100644 (file)
index 0000000..12e2a3c
--- /dev/null
@@ -0,0 +1,920 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ****************************************************************************
+ */
+
+#include "../wifi.h"
+#include "../base.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "hal_btc.h"
+
+static const u32 ofdmswing_table[OFDM_TABLE_SIZE] = {
+       0x7f8001fe,
+       0x788001e2,
+       0x71c001c7,
+       0x6b8001ae,
+       0x65400195,
+       0x5fc0017f,
+       0x5a400169,
+       0x55400155,
+       0x50800142,
+       0x4c000130,
+       0x47c0011f,
+       0x43c0010f,
+       0x40000100,
+       0x3c8000f2,
+       0x390000e4,
+       0x35c000d7,
+       0x32c000cb,
+       0x300000c0,
+       0x2d4000b5,
+       0x2ac000ab,
+       0x288000a2,
+       0x26000098,
+       0x24000090,
+       0x22000088,
+       0x20000080,
+       0x1e400079,
+       0x1c800072,
+       0x1b00006c,
+       0x19800066,
+       0x18000060,
+       0x16c0005b,
+       0x15800056,
+       0x14400051,
+       0x1300004c,
+       0x12000048,
+       0x11000044,
+       0x10000040,
+};
+
+static const u8 cckswing_table_ch1ch13[CCK_TABLE_SIZE][8] = {
+       {0x36, 0x35, 0x2e, 0x25, 0x1c, 0x12, 0x09, 0x04},
+       {0x33, 0x32, 0x2b, 0x23, 0x1a, 0x11, 0x08, 0x04},
+       {0x30, 0x2f, 0x29, 0x21, 0x19, 0x10, 0x08, 0x03},
+       {0x2d, 0x2d, 0x27, 0x1f, 0x18, 0x0f, 0x08, 0x03},
+       {0x2b, 0x2a, 0x25, 0x1e, 0x16, 0x0e, 0x07, 0x03},
+       {0x28, 0x28, 0x22, 0x1c, 0x15, 0x0d, 0x07, 0x03},
+       {0x26, 0x25, 0x21, 0x1b, 0x14, 0x0d, 0x06, 0x03},
+       {0x24, 0x23, 0x1f, 0x19, 0x13, 0x0c, 0x06, 0x03},
+       {0x22, 0x21, 0x1d, 0x18, 0x11, 0x0b, 0x06, 0x02},
+       {0x20, 0x20, 0x1b, 0x16, 0x11, 0x08, 0x05, 0x02},
+       {0x1f, 0x1e, 0x1a, 0x15, 0x10, 0x0a, 0x05, 0x02},
+       {0x1d, 0x1c, 0x18, 0x14, 0x0f, 0x0a, 0x05, 0x02},
+       {0x1b, 0x1a, 0x17, 0x13, 0x0e, 0x09, 0x04, 0x02},
+       {0x1a, 0x19, 0x16, 0x12, 0x0d, 0x09, 0x04, 0x02},
+       {0x18, 0x17, 0x15, 0x11, 0x0c, 0x08, 0x04, 0x02},
+       {0x17, 0x16, 0x13, 0x10, 0x0c, 0x08, 0x04, 0x02},
+       {0x16, 0x15, 0x12, 0x0f, 0x0b, 0x07, 0x04, 0x01},
+       {0x14, 0x14, 0x11, 0x0e, 0x0b, 0x07, 0x03, 0x02},
+       {0x13, 0x13, 0x10, 0x0d, 0x0a, 0x06, 0x03, 0x01},
+       {0x12, 0x12, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},
+       {0x11, 0x11, 0x0f, 0x0c, 0x09, 0x06, 0x03, 0x01},
+       {0x10, 0x10, 0x0e, 0x0b, 0x08, 0x05, 0x03, 0x01},
+       {0x0f, 0x0f, 0x0d, 0x0b, 0x08, 0x05, 0x03, 0x01},
+       {0x0e, 0x0e, 0x0c, 0x0a, 0x08, 0x05, 0x02, 0x01},
+       {0x0d, 0x0d, 0x0c, 0x0a, 0x07, 0x05, 0x02, 0x01},
+       {0x0d, 0x0c, 0x0b, 0x09, 0x07, 0x04, 0x02, 0x01},
+       {0x0c, 0x0c, 0x0a, 0x09, 0x06, 0x04, 0x02, 0x01},
+       {0x0b, 0x0b, 0x0a, 0x08, 0x06, 0x04, 0x02, 0x01},
+       {0x0b, 0x0a, 0x09, 0x08, 0x06, 0x04, 0x02, 0x01},
+       {0x0a, 0x0a, 0x09, 0x07, 0x05, 0x03, 0x02, 0x01},
+       {0x0a, 0x09, 0x08, 0x07, 0x05, 0x03, 0x02, 0x01},
+       {0x09, 0x09, 0x08, 0x06, 0x05, 0x03, 0x01, 0x01},
+       {0x09, 0x08, 0x07, 0x06, 0x04, 0x03, 0x01, 0x01}
+};
+
+static const u8 cckswing_table_ch14[CCK_TABLE_SIZE][8] = {
+       {0x36, 0x35, 0x2e, 0x1b, 0x00, 0x00, 0x00, 0x00},
+       {0x33, 0x32, 0x2b, 0x19, 0x00, 0x00, 0x00, 0x00},
+       {0x30, 0x2f, 0x29, 0x18, 0x00, 0x00, 0x00, 0x00},
+       {0x2d, 0x2d, 0x17, 0x17, 0x00, 0x00, 0x00, 0x00},
+       {0x2b, 0x2a, 0x25, 0x15, 0x00, 0x00, 0x00, 0x00},
+       {0x28, 0x28, 0x24, 0x14, 0x00, 0x00, 0x00, 0x00},
+       {0x26, 0x25, 0x21, 0x13, 0x00, 0x00, 0x00, 0x00},
+       {0x24, 0x23, 0x1f, 0x12, 0x00, 0x00, 0x00, 0x00},
+       {0x22, 0x21, 0x1d, 0x11, 0x00, 0x00, 0x00, 0x00},
+       {0x20, 0x20, 0x1b, 0x10, 0x00, 0x00, 0x00, 0x00},
+       {0x1f, 0x1e, 0x1a, 0x0f, 0x00, 0x00, 0x00, 0x00},
+       {0x1d, 0x1c, 0x18, 0x0e, 0x00, 0x00, 0x00, 0x00},
+       {0x1b, 0x1a, 0x17, 0x0e, 0x00, 0x00, 0x00, 0x00},
+       {0x1a, 0x19, 0x16, 0x0d, 0x00, 0x00, 0x00, 0x00},
+       {0x18, 0x17, 0x15, 0x0c, 0x00, 0x00, 0x00, 0x00},
+       {0x17, 0x16, 0x13, 0x0b, 0x00, 0x00, 0x00, 0x00},
+       {0x16, 0x15, 0x12, 0x0b, 0x00, 0x00, 0x00, 0x00},
+       {0x14, 0x14, 0x11, 0x0a, 0x00, 0x00, 0x00, 0x00},
+       {0x13, 0x13, 0x10, 0x0a, 0x00, 0x00, 0x00, 0x00},
+       {0x12, 0x12, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},
+       {0x11, 0x11, 0x0f, 0x09, 0x00, 0x00, 0x00, 0x00},
+       {0x10, 0x10, 0x0e, 0x08, 0x00, 0x00, 0x00, 0x00},
+       {0x0f, 0x0f, 0x0d, 0x08, 0x00, 0x00, 0x00, 0x00},
+       {0x0e, 0x0e, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00},
+       {0x0d, 0x0d, 0x0c, 0x07, 0x00, 0x00, 0x00, 0x00},
+       {0x0d, 0x0c, 0x0b, 0x06, 0x00, 0x00, 0x00, 0x00},
+       {0x0c, 0x0c, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00},
+       {0x0b, 0x0b, 0x0a, 0x06, 0x00, 0x00, 0x00, 0x00},
+       {0x0b, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00},
+       {0x0a, 0x0a, 0x09, 0x05, 0x00, 0x00, 0x00, 0x00},
+       {0x0a, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00},
+       {0x09, 0x09, 0x08, 0x05, 0x00, 0x00, 0x00, 0x00},
+       {0x09, 0x08, 0x07, 0x04, 0x00, 0x00, 0x00, 0x00}
+};
+
+static void rtl8723ae_dm_diginit(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+       dm_digtable->dig_enable_flag = true;
+       dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+       dm_digtable->cur_igvalue = 0x20;
+       dm_digtable->pre_igvalue = 0x0;
+       dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;
+       dm_digtable->presta_cstate = DIG_STA_DISCONNECT;
+       dm_digtable->curmultista_cstate = DIG_MULTISTA_DISCONNECT;
+       dm_digtable->rssi_lowthresh = DM_DIG_THRESH_LOW;
+       dm_digtable->rssi_highthresh = DM_DIG_THRESH_HIGH;
+       dm_digtable->fa_lowthresh = DM_FALSEALARM_THRESH_LOW;
+       dm_digtable->fa_highthresh = DM_FALSEALARM_THRESH_HIGH;
+       dm_digtable->rx_gain_range_max = DM_DIG_MAX;
+       dm_digtable->rx_gain_range_min = DM_DIG_MIN;
+       dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
+       dm_digtable->back_range_max = DM_DIG_BACKOFF_MAX;
+       dm_digtable->back_range_min = DM_DIG_BACKOFF_MIN;
+       dm_digtable->pre_cck_pd_state = CCK_PD_STAGE_MAX;
+       dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
+}
+
+static u8 rtl_init_gain_min_pwdb(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+       long rssi_val_min = 0;
+
+       if ((dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) &&
+           (dm_digtable->cursta_cstate == DIG_STA_CONNECT)) {
+               if (rtlpriv->dm.entry_min_undec_sm_pwdb != 0)
+                       rssi_val_min =
+                           (rtlpriv->dm.entry_min_undec_sm_pwdb >
+                            rtlpriv->dm.undec_sm_pwdb) ?
+                           rtlpriv->dm.undec_sm_pwdb :
+                           rtlpriv->dm.entry_min_undec_sm_pwdb;
+               else
+                       rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+       } else if (dm_digtable->cursta_cstate == DIG_STA_CONNECT ||
+                  dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT) {
+               rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+       } else if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) {
+               rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
+       }
+
+       return (u8) rssi_val_min;
+}
+
+static void rtl8723ae_dm_false_alarm_counter_statistics(struct ieee80211_hw *hw)
+{
+       u32 ret_value;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct false_alarm_statistics *falsealm_cnt = &(rtlpriv->falsealm_cnt);
+
+       ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER1, MASKDWORD);
+       falsealm_cnt->cnt_parity_fail = ((ret_value & 0xffff0000) >> 16);
+
+       ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER2, MASKDWORD);
+       falsealm_cnt->cnt_rate_illegal = (ret_value & 0xffff);
+       falsealm_cnt->cnt_crc8_fail = ((ret_value & 0xffff0000) >> 16);
+
+       ret_value = rtl_get_bbreg(hw, ROFDM_PHYCOUNTER3, MASKDWORD);
+       falsealm_cnt->cnt_mcs_fail = (ret_value & 0xffff);
+       falsealm_cnt->cnt_ofdm_fail = falsealm_cnt->cnt_parity_fail +
+           falsealm_cnt->cnt_rate_illegal +
+           falsealm_cnt->cnt_crc8_fail + falsealm_cnt->cnt_mcs_fail;
+
+       rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, BIT(14), 1);
+       ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERLOWER, MASKBYTE0);
+       falsealm_cnt->cnt_cck_fail = ret_value;
+
+       ret_value = rtl_get_bbreg(hw, RCCK0_FACOUNTERUPPER, MASKBYTE3);
+       falsealm_cnt->cnt_cck_fail += (ret_value & 0xff) << 8;
+       falsealm_cnt->cnt_all = (falsealm_cnt->cnt_parity_fail +
+                                falsealm_cnt->cnt_rate_illegal +
+                                falsealm_cnt->cnt_crc8_fail +
+                                falsealm_cnt->cnt_mcs_fail +
+                                falsealm_cnt->cnt_cck_fail);
+
+       rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 1);
+       rtl_set_bbreg(hw, ROFDM1_LSTF, 0x08000000, 0);
+       rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 0);
+       rtl_set_bbreg(hw, RCCK0_FALSEALARMREPORT, 0x0000c000, 2);
+
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+                "cnt_parity_fail = %d, cnt_rate_illegal = %d, "
+                "cnt_crc8_fail = %d, cnt_mcs_fail = %d\n",
+                falsealm_cnt->cnt_parity_fail,
+                falsealm_cnt->cnt_rate_illegal,
+                falsealm_cnt->cnt_crc8_fail, falsealm_cnt->cnt_mcs_fail);
+
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+                "cnt_ofdm_fail = %x, cnt_cck_fail = %x, cnt_all = %x\n",
+                falsealm_cnt->cnt_ofdm_fail,
+                falsealm_cnt->cnt_cck_fail, falsealm_cnt->cnt_all);
+}
+
+static void rtl92c_dm_ctrl_initgain_by_fa(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+       u8 value_igi = dm_digtable->cur_igvalue;
+
+       if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH0)
+               value_igi--;
+       else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH1)
+               value_igi += 0;
+       else if (rtlpriv->falsealm_cnt.cnt_all < DM_DIG_FA_TH2)
+               value_igi++;
+       else
+               value_igi += 2;
+
+       value_igi = clamp(value_igi, (u8)DM_DIG_FA_LOWER, (u8)DM_DIG_FA_UPPER);
+       if (rtlpriv->falsealm_cnt.cnt_all > 10000)
+               value_igi = 0x32;
+
+       dm_digtable->cur_igvalue = value_igi;
+       rtl8723ae_dm_write_dig(hw);
+}
+
+static void rtl92c_dm_ctrl_initgain_by_rssi(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dgtbl = &rtlpriv->dm_digtable;
+
+       if (rtlpriv->falsealm_cnt.cnt_all > dgtbl->fa_highthresh) {
+               if ((dgtbl->back_val - 2) < dgtbl->back_range_min)
+                       dgtbl->back_val = dgtbl->back_range_min;
+               else
+                       dgtbl->back_val -= 2;
+       } else if (rtlpriv->falsealm_cnt.cnt_all < dgtbl->fa_lowthresh) {
+               if ((dgtbl->back_val + 2) > dgtbl->back_range_max)
+                       dgtbl->back_val = dgtbl->back_range_max;
+               else
+                       dgtbl->back_val += 2;
+       }
+
+       if ((dgtbl->rssi_val_min + 10 - dgtbl->back_val) >
+           dgtbl->rx_gain_range_max)
+               dgtbl->cur_igvalue = dgtbl->rx_gain_range_max;
+       else if ((dgtbl->rssi_val_min + 10 -
+                 dgtbl->back_val) < dgtbl->rx_gain_range_min)
+               dgtbl->cur_igvalue = dgtbl->rx_gain_range_min;
+       else
+               dgtbl->cur_igvalue = dgtbl->rssi_val_min + 10 - dgtbl->back_val;
+
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+                "rssi_val_min = %x back_val %x\n",
+                dgtbl->rssi_val_min, dgtbl->back_val);
+
+       rtl8723ae_dm_write_dig(hw);
+}
+
+static void rtl8723ae_dm_initial_gain_multi_sta(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+       long rssi_strength = rtlpriv->dm.entry_min_undec_sm_pwdb;
+       bool multi_sta = false;
+
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               multi_sta = true;
+
+       if ((!multi_sta) ||
+           (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT)) {
+               rtlpriv->initialized = false;
+               dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+               return;
+       } else if (!rtlpriv->initialized) {
+               rtlpriv->initialized = true;
+               dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_0;
+               dm_digtable->cur_igvalue = 0x20;
+               rtl8723ae_dm_write_dig(hw);
+       }
+
+       if (dm_digtable->curmultista_cstate == DIG_MULTISTA_CONNECT) {
+               if ((rssi_strength < dm_digtable->rssi_lowthresh) &&
+                   (dm_digtable->dig_ext_port_stage != DIG_EXT_PORT_STAGE_1)) {
+
+                       if (dm_digtable->dig_ext_port_stage ==
+                           DIG_EXT_PORT_STAGE_2) {
+                               dm_digtable->cur_igvalue = 0x20;
+                               rtl8723ae_dm_write_dig(hw);
+                       }
+
+                       dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_1;
+               } else if (rssi_strength > dm_digtable->rssi_highthresh) {
+                       dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_2;
+                       rtl92c_dm_ctrl_initgain_by_fa(hw);
+               }
+       } else if (dm_digtable->dig_ext_port_stage != DIG_EXT_PORT_STAGE_0) {
+               dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_0;
+               dm_digtable->cur_igvalue = 0x20;
+               rtl8723ae_dm_write_dig(hw);
+       }
+
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+                "curmultista_cstate = %x dig_ext_port_stage %x\n",
+                dm_digtable->curmultista_cstate,
+                dm_digtable->dig_ext_port_stage);
+}
+
+static void rtl8723ae_dm_initial_gain_sta(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+                "presta_cstate = %x, cursta_cstate = %x\n",
+                dm_digtable->presta_cstate,
+                dm_digtable->cursta_cstate);
+
+       if (dm_digtable->presta_cstate == dm_digtable->cursta_cstate ||
+           dm_digtable->cursta_cstate == DIG_STA_BEFORE_CONNECT ||
+           dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
+
+               if (dm_digtable->cursta_cstate != DIG_STA_DISCONNECT) {
+                       dm_digtable->rssi_val_min = rtl_init_gain_min_pwdb(hw);
+                       rtl92c_dm_ctrl_initgain_by_rssi(hw);
+               }
+       } else {
+               dm_digtable->rssi_val_min = 0;
+               dm_digtable->dig_ext_port_stage = DIG_EXT_PORT_STAGE_MAX;
+               dm_digtable->back_val = DM_DIG_BACKOFF_DEFAULT;
+               dm_digtable->cur_igvalue = 0x20;
+               dm_digtable->pre_igvalue = 0;
+               rtl8723ae_dm_write_dig(hw);
+       }
+}
+static void rtl8723ae_dm_cck_packet_detection_thresh(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+       if (dm_digtable->cursta_cstate == DIG_STA_CONNECT) {
+               dm_digtable->rssi_val_min = rtl_init_gain_min_pwdb(hw);
+
+               if (dm_digtable->pre_cck_pd_state == CCK_PD_STAGE_LowRssi) {
+                       if (dm_digtable->rssi_val_min <= 25)
+                               dm_digtable->cur_cck_pd_state =
+                                   CCK_PD_STAGE_LowRssi;
+                       else
+                               dm_digtable->cur_cck_pd_state =
+                                   CCK_PD_STAGE_HighRssi;
+               } else {
+                       if (dm_digtable->rssi_val_min <= 20)
+                               dm_digtable->cur_cck_pd_state =
+                                   CCK_PD_STAGE_LowRssi;
+                       else
+                               dm_digtable->cur_cck_pd_state =
+                                   CCK_PD_STAGE_HighRssi;
+               }
+       } else {
+               dm_digtable->cur_cck_pd_state = CCK_PD_STAGE_MAX;
+       }
+
+       if (dm_digtable->pre_cck_pd_state != dm_digtable->cur_cck_pd_state) {
+               if (dm_digtable->cur_cck_pd_state == CCK_PD_STAGE_LowRssi) {
+                       if (rtlpriv->falsealm_cnt.cnt_cck_fail > 800)
+                               dm_digtable->cur_cck_fa_state =
+                                   CCK_FA_STAGE_High;
+                       else
+                               dm_digtable->cur_cck_fa_state =
+                                                        CCK_FA_STAGE_Low;
+
+                       if (dm_digtable->pre_cck_fa_state !=
+                           dm_digtable->cur_cck_fa_state) {
+                               if (dm_digtable->cur_cck_fa_state ==
+                                   CCK_FA_STAGE_Low)
+                                       rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2,
+                                                     0x83);
+                               else
+                                       rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2,
+                                                     0xcd);
+
+                               dm_digtable->pre_cck_fa_state =
+                                   dm_digtable->cur_cck_fa_state;
+                       }
+
+                       rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x40);
+
+               } else {
+                       rtl_set_bbreg(hw, RCCK0_CCA, MASKBYTE2, 0xcd);
+                       rtl_set_bbreg(hw, RCCK0_SYSTEM, MASKBYTE1, 0x47);
+
+               }
+               dm_digtable->pre_cck_pd_state = dm_digtable->cur_cck_pd_state;
+       }
+
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_TRACE,
+                "CCKPDStage=%x\n", dm_digtable->cur_cck_pd_state);
+
+}
+
+static void rtl8723ae_dm_ctrl_initgain_by_twoport(struct ieee80211_hw *hw)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+       if (mac->act_scanning == true)
+               return;
+
+       if (mac->link_state >= MAC80211_LINKED)
+               dm_digtable->cursta_cstate = DIG_STA_CONNECT;
+       else
+               dm_digtable->cursta_cstate = DIG_STA_DISCONNECT;
+
+       rtl8723ae_dm_initial_gain_sta(hw);
+       rtl8723ae_dm_initial_gain_multi_sta(hw);
+       rtl8723ae_dm_cck_packet_detection_thresh(hw);
+
+       dm_digtable->presta_cstate = dm_digtable->cursta_cstate;
+
+}
+
+static void rtl8723ae_dm_dig(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+       if (rtlpriv->dm.dm_initialgain_enable == false)
+               return;
+       if (dm_digtable->dig_enable_flag == false)
+               return;
+
+       rtl8723ae_dm_ctrl_initgain_by_twoport(hw);
+}
+
+static void rtl8723ae_dm_init_dynamic_txpower(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm.dynamic_txpower_enable = false;
+
+       rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+       rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+}
+
+static void rtl8723ae_dm_dynamic_txpower(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       long undec_sm_pwdb;
+
+       if (!rtlpriv->dm.dynamic_txpower_enable)
+               return;
+
+       if (rtlpriv->dm.dm_flag & HAL_DM_HIPWR_DISABLE) {
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+               return;
+       }
+
+       if ((mac->link_state < MAC80211_LINKED) &&
+           (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+                        "Not connected\n");
+
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+
+               rtlpriv->dm.last_dtp_lvl = TXHIGHPWRLEVEL_NORMAL;
+               return;
+       }
+
+       if (mac->link_state >= MAC80211_LINKED) {
+               if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+                       undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
+                       RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                                "AP Client PWDB = 0x%lx\n",
+                                undec_sm_pwdb);
+               } else {
+                       undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
+                       RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                                "STA Default Port PWDB = 0x%lx\n",
+                                undec_sm_pwdb);
+               }
+       } else {
+               undec_sm_pwdb = rtlpriv->dm.entry_min_undec_sm_pwdb;
+
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        "AP Ext Port PWDB = 0x%lx\n",
+                         undec_sm_pwdb);
+       }
+
+       if (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL2) {
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x0)\n");
+       } else if ((undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL2 - 3)) &&
+                  (undec_sm_pwdb >= TX_POWER_NEAR_FIELD_THRESH_LVL1)) {
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_LEVEL1;
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        "TXHIGHPWRLEVEL_LEVEL1 (TxPwr=0x10)\n");
+       } else if (undec_sm_pwdb < (TX_POWER_NEAR_FIELD_THRESH_LVL1 - 5)) {
+               rtlpriv->dm.dynamic_txhighpower_lvl = TXHIGHPWRLEVEL_NORMAL;
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        "TXHIGHPWRLEVEL_NORMAL\n");
+       }
+
+       if ((rtlpriv->dm.dynamic_txhighpower_lvl != rtlpriv->dm.last_dtp_lvl)) {
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        "PHY_SetTxPowerLevel8192S() Channel = %d\n",
+                         rtlphy->current_channel);
+               rtl8723ae_phy_set_txpower_level(hw, rtlphy->current_channel);
+       }
+
+       rtlpriv->dm.last_dtp_lvl = rtlpriv->dm.dynamic_txhighpower_lvl;
+}
+
+void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+       RT_TRACE(rtlpriv, COMP_DIG, DBG_LOUD,
+                "cur_igvalue = 0x%x, "
+                "pre_igvalue = 0x%x, back_val = %d\n",
+                dm_digtable->cur_igvalue, dm_digtable->pre_igvalue,
+                dm_digtable->back_val);
+
+       if (dm_digtable->pre_igvalue != dm_digtable->cur_igvalue) {
+               rtl_set_bbreg(hw, ROFDM0_XAAGCCORE1, 0x7f,
+                             dm_digtable->cur_igvalue);
+               rtl_set_bbreg(hw, ROFDM0_XBAGCCORE1, 0x7f,
+                             dm_digtable->cur_igvalue);
+
+               dm_digtable->pre_igvalue = dm_digtable->cur_igvalue;
+       }
+}
+
+static void rtl8723ae_dm_pwdmonitor(struct ieee80211_hw *hw)
+{
+}
+
+void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm.current_turbo_edca = false;
+       rtlpriv->dm.is_any_nonbepkts = false;
+       rtlpriv->dm.is_cur_rdlstate = false;
+}
+
+static void rtl8723ae_dm_check_edca_turbo(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+
+       u64 cur_txok_cnt = 0;
+       u64 cur_rxok_cnt = 0;
+       u32 edca_be_ul = 0x5ea42b;
+       u32 edca_be_dl = 0x5ea42b;
+       bool bt_change_edca = false;
+
+       if ((mac->last_bt_edca_ul != rtlpcipriv->bt_coexist.bt_edca_ul) ||
+           (mac->last_bt_edca_dl != rtlpcipriv->bt_coexist.bt_edca_dl)) {
+               rtlpriv->dm.current_turbo_edca = false;
+               mac->last_bt_edca_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+               mac->last_bt_edca_dl = rtlpcipriv->bt_coexist.bt_edca_dl;
+       }
+
+       if (rtlpcipriv->bt_coexist.bt_edca_ul != 0) {
+               edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_ul;
+               bt_change_edca = true;
+       }
+
+       if (rtlpcipriv->bt_coexist.bt_edca_dl != 0) {
+               edca_be_ul = rtlpcipriv->bt_coexist.bt_edca_dl;
+               bt_change_edca = true;
+       }
+
+       if (mac->link_state != MAC80211_LINKED) {
+               rtlpriv->dm.current_turbo_edca = false;
+               return;
+       }
+
+       if ((!mac->ht_enable) && (!rtlpcipriv->bt_coexist.bt_coexistence)) {
+               if (!(edca_be_ul & 0xffff0000))
+                       edca_be_ul |= 0x005e0000;
+
+               if (!(edca_be_dl & 0xffff0000))
+                       edca_be_dl |= 0x005e0000;
+       }
+
+       if ((bt_change_edca) || ((!rtlpriv->dm.is_any_nonbepkts) &&
+            (!rtlpriv->dm.disable_framebursting))) {
+
+               cur_txok_cnt = rtlpriv->stats.txbytesunicast -
+                              mac->last_txok_cnt;
+               cur_rxok_cnt = rtlpriv->stats.rxbytesunicast -
+                              mac->last_rxok_cnt;
+
+               if (cur_rxok_cnt > 4 * cur_txok_cnt) {
+                       if (!rtlpriv->dm.is_cur_rdlstate ||
+                           !rtlpriv->dm.current_turbo_edca) {
+                               rtl_write_dword(rtlpriv,
+                                               REG_EDCA_BE_PARAM,
+                                               edca_be_dl);
+                               rtlpriv->dm.is_cur_rdlstate = true;
+                       }
+               } else {
+                       if (rtlpriv->dm.is_cur_rdlstate ||
+                           !rtlpriv->dm.current_turbo_edca) {
+                               rtl_write_dword(rtlpriv,
+                                               REG_EDCA_BE_PARAM,
+                                               edca_be_ul);
+                               rtlpriv->dm.is_cur_rdlstate = false;
+                       }
+               }
+               rtlpriv->dm.current_turbo_edca = true;
+       } else {
+               if (rtlpriv->dm.current_turbo_edca) {
+                       u8 tmp = AC0_BE;
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                     HW_VAR_AC_PARAM,
+                                                     (u8 *) (&tmp));
+                       rtlpriv->dm.current_turbo_edca = false;
+               }
+       }
+
+       rtlpriv->dm.is_any_nonbepkts = false;
+       mac->last_txok_cnt = rtlpriv->stats.txbytesunicast;
+       mac->last_rxok_cnt = rtlpriv->stats.rxbytesunicast;
+}
+
+static void rtl8723ae_dm_initialize_txpower_tracking(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm.txpower_tracking = true;
+       rtlpriv->dm.txpower_trackinginit = false;
+
+       RT_TRACE(rtlpriv, COMP_POWER_TRACKING, DBG_LOUD,
+                "pMgntInfo->txpower_tracking = %d\n",
+                rtlpriv->dm.txpower_tracking);
+}
+
+void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rate_adaptive *p_ra = &(rtlpriv->ra);
+
+       p_ra->ratr_state = DM_RATR_STA_INIT;
+       p_ra->pre_ratr_state = DM_RATR_STA_INIT;
+
+       if (rtlpriv->dm.dm_type == DM_TYPE_BYDRIVER)
+               rtlpriv->dm.useramask = true;
+       else
+               rtlpriv->dm.useramask = false;
+}
+
+static void rtl8723ae_dm_init_dynamic_bpowersaving(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm_pstable.pre_ccastate = CCA_MAX;
+       rtlpriv->dm_pstable.cur_ccasate = CCA_MAX;
+       rtlpriv->dm_pstable.pre_rfstate = RF_MAX;
+       rtlpriv->dm_pstable.cur_rfstate = RF_MAX;
+       rtlpriv->dm_pstable.rssi_val_min = 0;
+}
+
+void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 force_in_normal)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ps_t *dm_pstable = &rtlpriv->dm_pstable;
+
+       if (!rtlpriv->reg_init) {
+               rtlpriv->reg_874 = (rtl_get_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+                                   MASKDWORD) & 0x1CC000) >> 14;
+
+               rtlpriv->reg_c70 = (rtl_get_bbreg(hw, ROFDM0_AGCPARAMETER1,
+                                   MASKDWORD) & BIT(3)) >> 3;
+
+               rtlpriv->reg_85c = (rtl_get_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
+                                   MASKDWORD) & 0xFF000000) >> 24;
+
+               rtlpriv->reg_a74 = (rtl_get_bbreg(hw, 0xa74, MASKDWORD) &
+                                  0xF000) >> 12;
+
+               rtlpriv->reg_init = true;
+       }
+
+       if (!force_in_normal) {
+               if (dm_pstable->rssi_val_min != 0) {
+                       if (dm_pstable->pre_rfstate == RF_NORMAL) {
+                               if (dm_pstable->rssi_val_min >= 30)
+                                       dm_pstable->cur_rfstate = RF_SAVE;
+                               else
+                                       dm_pstable->cur_rfstate = RF_NORMAL;
+                       } else {
+                               if (dm_pstable->rssi_val_min <= 25)
+                                       dm_pstable->cur_rfstate = RF_NORMAL;
+                               else
+                                       dm_pstable->cur_rfstate = RF_SAVE;
+                       }
+               } else {
+                       dm_pstable->cur_rfstate = RF_MAX;
+               }
+       } else {
+               dm_pstable->cur_rfstate = RF_NORMAL;
+       }
+
+       if (dm_pstable->pre_rfstate != dm_pstable->cur_rfstate) {
+               if (dm_pstable->cur_rfstate == RF_SAVE) {
+
+                       rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+                                     BIT(5), 0x1);
+                       rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+                                     0x1C0000, 0x2);
+                       rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3), 0);
+                       rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL,
+                                     0xFF000000, 0x63);
+                       rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+                                     0xC000, 0x2);
+                       rtl_set_bbreg(hw, 0xa74, 0xF000, 0x3);
+                       rtl_set_bbreg(hw, 0x818, BIT(28), 0x0);
+                       rtl_set_bbreg(hw, 0x818, BIT(28), 0x1);
+               } else {
+                       rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+                                     0x1CC000, rtlpriv->reg_874);
+                       rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, BIT(3),
+                                     rtlpriv->reg_c70);
+                       rtl_set_bbreg(hw, RFPGA0_XCD_SWITCHCONTROL, 0xFF000000,
+                                     rtlpriv->reg_85c);
+                       rtl_set_bbreg(hw, 0xa74, 0xF000, rtlpriv->reg_a74);
+                       rtl_set_bbreg(hw, 0x818, BIT(28), 0x0);
+                       rtl_set_bbreg(hw, RFPGA0_XCD_RFINTERFACESW,
+                                     BIT(5), 0x0);
+               }
+
+               dm_pstable->pre_rfstate = dm_pstable->cur_rfstate;
+       }
+}
+
+static void rtl8723ae_dm_dynamic_bpowersaving(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct ps_t *dm_pstable = &rtlpriv->dm_pstable;
+
+       if (((mac->link_state == MAC80211_NOLINK)) &&
+           (rtlpriv->dm.entry_min_undec_sm_pwdb == 0)) {
+               dm_pstable->rssi_val_min = 0;
+               RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
+                        "Not connected to any\n");
+       }
+
+       if (mac->link_state == MAC80211_LINKED) {
+               if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+                       dm_pstable->rssi_val_min =
+                           rtlpriv->dm.entry_min_undec_sm_pwdb;
+                       RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
+                                "AP Client PWDB = 0x%lx\n",
+                                dm_pstable->rssi_val_min);
+               } else {
+                       dm_pstable->rssi_val_min = rtlpriv->dm.undec_sm_pwdb;
+                       RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
+                                "STA Default Port PWDB = 0x%lx\n",
+                                dm_pstable->rssi_val_min);
+               }
+       } else {
+               dm_pstable->rssi_val_min = rtlpriv->dm.entry_min_undec_sm_pwdb;
+
+               RT_TRACE(rtlpriv, DBG_LOUD, DBG_LOUD,
+                        "AP Ext Port PWDB = 0x%lx\n",
+                        dm_pstable->rssi_val_min);
+       }
+
+       rtl8723ae_dm_rf_saving(hw, false);
+}
+
+void rtl8723ae_dm_init(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->dm.dm_type = DM_TYPE_BYDRIVER;
+       rtl8723ae_dm_diginit(hw);
+       rtl8723ae_dm_init_dynamic_txpower(hw);
+       rtl8723ae_dm_init_edca_turbo(hw);
+       rtl8723ae_dm_init_rate_adaptive_mask(hw);
+       rtl8723ae_dm_initialize_txpower_tracking(hw);
+       rtl8723ae_dm_init_dynamic_bpowersaving(hw);
+}
+
+void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       bool fw_current_inpsmode = false;
+       bool fw_ps_awake = true;
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+                                     (u8 *) (&fw_current_inpsmode));
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
+                                     (u8 *) (&fw_ps_awake));
+
+       if ((ppsc->rfpwr_state == ERFON) &&
+           ((!fw_current_inpsmode) && fw_ps_awake) &&
+           (!ppsc->rfchange_inprogress)) {
+               rtl8723ae_dm_pwdmonitor(hw);
+               rtl8723ae_dm_dig(hw);
+               rtl8723ae_dm_false_alarm_counter_statistics(hw);
+               rtl8723ae_dm_dynamic_bpowersaving(hw);
+               rtl8723ae_dm_dynamic_txpower(hw);
+               /* rtl92c_dm_refresh_rate_adaptive_mask(hw); */
+               rtl8723ae_dm_bt_coexist(hw);
+               rtl8723ae_dm_check_edca_turbo(hw);
+       }
+       if (rtlpcipriv->bt_coexist.init_set)
+               rtl_write_byte(rtlpriv, 0x76e, 0xc);
+}
+
+static void rtl8723ae_dm_init_bt_coexist(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       rtlpcipriv->bt_coexist.bt_rfreg_origin_1e
+               = rtl_get_rfreg(hw, (enum radio_path)0, RF_RCK1, 0xfffff);
+       rtlpcipriv->bt_coexist.bt_rfreg_origin_1f
+               = rtl_get_rfreg(hw, (enum radio_path)0, RF_RCK2, 0xf0);
+
+       rtlpcipriv->bt_coexist.cstate = 0;
+       rtlpcipriv->bt_coexist.previous_state = 0;
+       rtlpcipriv->bt_coexist.cstate_h = 0;
+       rtlpcipriv->bt_coexist.previous_state_h = 0;
+       rtlpcipriv->bt_coexist.lps_counter = 0;
+
+       /*  Enable counter statistics */
+       rtl_write_byte(rtlpriv, 0x76e, 0x4);
+       rtl_write_byte(rtlpriv, 0x778, 0x3);
+       rtl_write_byte(rtlpriv, 0x40, 0x20);
+
+       rtlpcipriv->bt_coexist.init_set = true;
+}
+
+void rtl8723ae_dm_bt_coexist(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       u8 tmp_byte = 0;
+       if (!rtlpcipriv->bt_coexist.bt_coexistence) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
+                        "[DM]{BT], BT not exist!!\n");
+               return;
+       }
+
+       if (!rtlpcipriv->bt_coexist.init_set) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
+                        "[DM][BT], rtl8723ae_dm_bt_coexist()\n");
+
+               rtl8723ae_dm_init_bt_coexist(hw);
+       }
+
+       tmp_byte = rtl_read_byte(rtlpriv, 0x40);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_LOUD,
+                "[DM][BT], 0x40 is 0x%x", tmp_byte);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "[DM][BT], bt_dm_coexist start");
+       rtl8723ae_dm_bt_coexist_8723(hw);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h b/drivers/net/wireless/rtlwifi/rtl8723ae/dm.h
new file mode 100644 (file)
index 0000000..39d2461
--- /dev/null
@@ -0,0 +1,149 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ****************************************************************************
+ */
+
+#ifndef        __RTL8723E_DM_H__
+#define __RTL8723E_DM_H__
+
+#define HAL_DM_HIPWR_DISABLE                   BIT(1)
+
+#define OFDM_TABLE_SIZE                                37
+#define CCK_TABLE_SIZE                         33
+
+#define DM_DIG_THRESH_HIGH                     40
+#define DM_DIG_THRESH_LOW                      35
+
+#define DM_FALSEALARM_THRESH_LOW               400
+#define DM_FALSEALARM_THRESH_HIGH              1000
+
+#define DM_DIG_MAX                             0x3e
+#define DM_DIG_MIN                             0x1e
+
+#define DM_DIG_FA_UPPER                                0x32
+#define DM_DIG_FA_LOWER                                0x20
+#define DM_DIG_FA_TH0                          0x20
+#define DM_DIG_FA_TH1                          0x100
+#define DM_DIG_FA_TH2                          0x200
+
+#define DM_DIG_BACKOFF_MAX                     12
+#define DM_DIG_BACKOFF_MIN                     -4
+#define DM_DIG_BACKOFF_DEFAULT                 10
+
+#define DM_RATR_STA_INIT                       0
+
+#define TXHIGHPWRLEVEL_NORMAL                  0
+#define TXHIGHPWRLEVEL_LEVEL1                  1
+#define TXHIGHPWRLEVEL_LEVEL2                  2
+#define TXHIGHPWRLEVEL_BT1                     3
+#define TXHIGHPWRLEVEL_BT2                     4
+
+#define DM_TYPE_BYDRIVER                       1
+
+#define TX_POWER_NEAR_FIELD_THRESH_LVL2                74
+#define TX_POWER_NEAR_FIELD_THRESH_LVL1                67
+
+struct swat_t {
+       u8 failure_cnt;
+       u8 try_flag;
+       u8 stop_trying;
+       long pre_rssi;
+       long trying_threshold;
+       u8 cur_antenna;
+       u8 pre_antenna;
+};
+
+enum tag_dynamic_init_gain_operation_type_definition {
+       DIG_TYPE_THRESH_HIGH = 0,
+       DIG_TYPE_THRESH_LOW = 1,
+       DIG_TYPE_BACKOFF = 2,
+       DIG_TYPE_RX_GAIN_MIN = 3,
+       DIG_TYPE_RX_GAIN_MAX = 4,
+       DIG_TYPE_ENABLE = 5,
+       DIG_TYPE_DISABLE = 6,
+       DIG_OP_TYPE_MAX
+};
+
+enum tag_cck_packet_detection_threshold_type_definition {
+       CCK_PD_STAGE_LowRssi = 0,
+       CCK_PD_STAGE_HighRssi = 1,
+       CCK_FA_STAGE_Low = 2,
+       CCK_FA_STAGE_High = 3,
+       CCK_PD_STAGE_MAX = 4,
+};
+
+enum dm_1r_cca_e {
+       CCA_1R = 0,
+       CCA_2R = 1,
+       CCA_MAX = 2,
+};
+
+enum dm_rf_e {
+       RF_SAVE = 0,
+       RF_NORMAL = 1,
+       RF_MAX = 2,
+};
+
+enum dm_sw_ant_switch_e {
+       ANS_ANTENNA_B = 1,
+       ANS_ANTENNA_A = 2,
+       ANS_ANTENNA_MAX = 3,
+};
+
+enum dm_dig_ext_port_alg_e {
+       DIG_EXT_PORT_STAGE_0 = 0,
+       DIG_EXT_PORT_STAGE_1 = 1,
+       DIG_EXT_PORT_STAGE_2 = 2,
+       DIG_EXT_PORT_STAGE_3 = 3,
+       DIG_EXT_PORT_STAGE_MAX = 4,
+};
+
+enum dm_dig_connect_e {
+       DIG_STA_DISCONNECT = 0,
+       DIG_STA_CONNECT = 1,
+       DIG_STA_BEFORE_CONNECT = 2,
+       DIG_MULTISTA_DISCONNECT = 3,
+       DIG_MULTISTA_CONNECT = 4,
+       DIG_CONNECT_MAX
+};
+
+#define GET_UNDECORATED_AVERAGE_RSSI(_priv)     \
+       ((((struct rtl_priv *)(_priv))->mac80211.opmode ==      \
+       NL80211_IFTYPE_ADHOC) ?  \
+       (((struct rtl_priv *)(_priv))->dm.entry_min_undec_sm_pwdb) \
+       : (((struct rtl_priv *)(_priv))->dm.undec_sm_pwdb))
+
+void rtl8723ae_dm_init(struct ieee80211_hw *hw);
+void rtl8723ae_dm_watchdog(struct ieee80211_hw *hw);
+void rtl8723ae_dm_write_dig(struct ieee80211_hw *hw);
+void rtl8723ae_dm_init_edca_turbo(struct ieee80211_hw *hw);
+void rtl8723ae_dm_init_rate_adaptive_mask(struct ieee80211_hw *hw);
+void rtl8723ae_dm_rf_saving(struct ieee80211_hw *hw, u8 bforce_in_normal);
+void rtl8723ae_dm_bt_coexist(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.c
new file mode 100644 (file)
index 0000000..f55b176
--- /dev/null
@@ -0,0 +1,745 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ****************************************************************************
+ */
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "reg.h"
+#include "def.h"
+#include "fw.h"
+
+static void _rtl8723ae_enable_fw_download(struct ieee80211_hw *hw, bool enable)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmp;
+       if (enable) {
+               tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+               rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, tmp | 0x04);
+
+               tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+               rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp | 0x01);
+
+               tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL + 2);
+               rtl_write_byte(rtlpriv, REG_MCUFWDL + 2, tmp & 0xf7);
+       } else {
+               tmp = rtl_read_byte(rtlpriv, REG_MCUFWDL);
+               rtl_write_byte(rtlpriv, REG_MCUFWDL, tmp & 0xfe);
+
+               rtl_write_byte(rtlpriv, REG_MCUFWDL + 1, 0x00);
+       }
+}
+
+static void _rtl8723ae_fw_block_write(struct ieee80211_hw *hw,
+                                     const u8 *buffer, u32 size)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 blockSize = sizeof(u32);
+       u8 *bufferPtr = (u8 *) buffer;
+       u32 *pu4BytePtr = (u32 *) buffer;
+       u32 i, offset, blockCount, remainSize;
+
+       blockCount = size / blockSize;
+       remainSize = size % blockSize;
+
+       for (i = 0; i < blockCount; i++) {
+               offset = i * blockSize;
+               rtl_write_dword(rtlpriv, (FW_8192C_START_ADDRESS + offset),
+                               *(pu4BytePtr + i));
+       }
+
+       if (remainSize) {
+               offset = blockCount * blockSize;
+               bufferPtr += offset;
+               for (i = 0; i < remainSize; i++) {
+                       rtl_write_byte(rtlpriv, (FW_8192C_START_ADDRESS +
+                                                offset + i), *(bufferPtr + i));
+               }
+       }
+}
+
+static void _rtl8723ae_fw_page_write(struct ieee80211_hw *hw,
+                                    u32 page, const u8 *buffer, u32 size)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 value8;
+       u8 u8page = (u8) (page & 0x07);
+
+       value8 = (rtl_read_byte(rtlpriv, REG_MCUFWDL + 2) & 0xF8) | u8page;
+
+       rtl_write_byte(rtlpriv, (REG_MCUFWDL + 2), value8);
+       _rtl8723ae_fw_block_write(hw, buffer, size);
+}
+
+static void _rtl8723ae_write_fw(struct ieee80211_hw *hw,
+                               enum version_8723e version, u8 *buffer,
+                               u32 size)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 *bufferPtr = (u8 *) buffer;
+       u32 page_nums, remain_size;
+       u32 page, offset;
+
+       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW size is %d bytes,\n", size);
+
+       page_nums = size / FW_8192C_PAGE_SIZE;
+       remain_size = size % FW_8192C_PAGE_SIZE;
+
+       if (page_nums > 6) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Page numbers should not be greater then 6\n");
+       }
+
+       for (page = 0; page < page_nums; page++) {
+               offset = page * FW_8192C_PAGE_SIZE;
+               _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
+                                        FW_8192C_PAGE_SIZE);
+       }
+
+       if (remain_size) {
+               offset = page_nums * FW_8192C_PAGE_SIZE;
+               page = page_nums;
+               _rtl8723ae_fw_page_write(hw, page, (bufferPtr + offset),
+                                        remain_size);
+       }
+
+       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE, "FW write done.\n");
+}
+
+static int _rtl8723ae_fw_free_to_go(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int err = -EIO;
+       u32 counter = 0;
+       u32 value32;
+
+       do {
+               value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+       } while ((counter++ < FW_8192C_POLLING_TIMEOUT_COUNT) &&
+                (!(value32 & FWDL_ChkSum_rpt)));
+
+       if (counter >= FW_8192C_POLLING_TIMEOUT_COUNT) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "chksum report faill ! REG_MCUFWDL:0x%08x .\n",
+                        value32);
+               goto exit;
+       }
+
+       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+                "Checksum report OK ! REG_MCUFWDL:0x%08x .\n", value32);
+
+       value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+       value32 |= MCUFWDL_RDY;
+       value32 &= ~WINTINI_RDY;
+       rtl_write_dword(rtlpriv, REG_MCUFWDL, value32);
+
+       counter = 0;
+
+       do {
+               value32 = rtl_read_dword(rtlpriv, REG_MCUFWDL);
+               if (value32 & WINTINI_RDY) {
+                       RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+                                "Polling FW ready success!! REG_MCUFWDL:0x%08x .\n",
+                                value32);
+                       err = 0;
+                       goto exit;
+               }
+
+               mdelay(FW_8192C_POLLING_DELAY);
+
+       } while (counter++ < FW_8192C_POLLING_TIMEOUT_COUNT);
+
+       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                "Polling FW ready fail!! REG_MCUFWDL:0x%08x .\n", value32);
+
+exit:
+       return err;
+}
+
+int rtl8723ae_download_fw(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl8723ae_firmware_header *pfwheader;
+       u8 *pfwdata;
+       u32 fwsize;
+       int err;
+       enum version_8723e version = rtlhal->version;
+
+       if (!rtlhal->pfirmware)
+               return 1;
+
+       pfwheader = (struct rtl8723ae_firmware_header *)rtlhal->pfirmware;
+       pfwdata = (u8 *) rtlhal->pfirmware;
+       fwsize = rtlhal->fwsize;
+
+       if (IS_FW_HEADER_EXIST(pfwheader)) {
+               RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+                        "Firmware Version(%d), Signature(%#x),Size(%d)\n",
+                        pfwheader->version, pfwheader->signature,
+                        (int)sizeof(struct rtl8723ae_firmware_header));
+
+               pfwdata = pfwdata + sizeof(struct rtl8723ae_firmware_header);
+               fwsize = fwsize - sizeof(struct rtl8723ae_firmware_header);
+       }
+
+       if (rtl_read_byte(rtlpriv, REG_MCUFWDL)&BIT(7)) {
+               rtl8723ae_firmware_selfreset(hw);
+               rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+       }
+       _rtl8723ae_enable_fw_download(hw, true);
+       _rtl8723ae_write_fw(hw, version, pfwdata, fwsize);
+       _rtl8723ae_enable_fw_download(hw, false);
+
+       err = _rtl8723ae_fw_free_to_go(hw);
+       if (err) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Firmware is not ready to run!\n");
+       } else {
+               RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+                        "Firmware is ready to run!\n");
+       }
+       return 0;
+}
+
+static bool rtl8723ae_check_fw_read_last_h2c(struct ieee80211_hw *hw, u8 boxnum)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 val_hmetfr, val_mcutst_1;
+       bool result = false;
+
+       val_hmetfr = rtl_read_byte(rtlpriv, REG_HMETFR);
+       val_mcutst_1 = rtl_read_byte(rtlpriv, (REG_MCUTST_1 + boxnum));
+
+       if (((val_hmetfr >> boxnum) & BIT(0)) == 0 && val_mcutst_1 == 0)
+               result = true;
+       return result;
+}
+
+static void _rtl8723ae_fill_h2c_command(struct ieee80211_hw *hw,
+                                       u8 element_id, u32 cmd_len,
+                                       u8 *p_cmdbuffer)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 boxnum;
+       u16 box_reg = 0, box_extreg = 0;
+       u8 u1tmp;
+       bool isfw_rd = false;
+       bool bwrite_sucess = false;
+       u8 wait_h2c_limmit = 100;
+       u8 wait_writeh2c_limmit = 100;
+       u8 boxcontent[4], boxextcontent[2];
+       u32 h2c_waitcounter = 0;
+       unsigned long flag;
+       u8 idx;
+
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "come in\n");
+
+       while (true) {
+               spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+               if (rtlhal->h2c_setinprogress) {
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                "H2C set in progress! Wait to set..element_id(%d).\n",
+                                element_id);
+
+                       while (rtlhal->h2c_setinprogress) {
+                               spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock,
+                                                      flag);
+                               h2c_waitcounter++;
+                               RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                        "Wait 100 us (%d times)...\n",
+                                        h2c_waitcounter);
+                               udelay(100);
+
+                               if (h2c_waitcounter > 1000)
+                                       return;
+                               spin_lock_irqsave(&rtlpriv->locks.h2c_lock,
+                                                 flag);
+                       }
+                       spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+               } else {
+                       rtlhal->h2c_setinprogress = true;
+                       spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+                       break;
+               }
+       }
+
+       while (!bwrite_sucess) {
+               wait_writeh2c_limmit--;
+               if (wait_writeh2c_limmit == 0) {
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "Write H2C fail because no trigger "
+                                "for FW INT!\n");
+                       break;
+               }
+
+               boxnum = rtlhal->last_hmeboxnum;
+               switch (boxnum) {
+               case 0:
+                       box_reg = REG_HMEBOX_0;
+                       box_extreg = REG_HMEBOX_EXT_0;
+                       break;
+               case 1:
+                       box_reg = REG_HMEBOX_1;
+                       box_extreg = REG_HMEBOX_EXT_1;
+                       break;
+               case 2:
+                       box_reg = REG_HMEBOX_2;
+                       box_extreg = REG_HMEBOX_EXT_2;
+                       break;
+               case 3:
+                       box_reg = REG_HMEBOX_3;
+                       box_extreg = REG_HMEBOX_EXT_3;
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not processed\n");
+                       break;
+               }
+
+               isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum);
+               while (!isfw_rd) {
+
+                       wait_h2c_limmit--;
+                       if (wait_h2c_limmit == 0) {
+                               RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                        "Wating too long for FW read clear HMEBox(%d)!\n",
+                                        boxnum);
+                               break;
+                       }
+
+                       udelay(10);
+
+                       isfw_rd = rtl8723ae_check_fw_read_last_h2c(hw, boxnum);
+                       u1tmp = rtl_read_byte(rtlpriv, 0x1BF);
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                "Wating for FW read clear HMEBox(%d)!!! "
+                                "0x1BF = %2x\n", boxnum, u1tmp);
+               }
+
+               if (!isfw_rd) {
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                                "Write H2C register BOX[%d] fail!!!!! "
+                                "Fw do not read.\n", boxnum);
+                       break;
+               }
+
+               memset(boxcontent, 0, sizeof(boxcontent));
+               memset(boxextcontent, 0, sizeof(boxextcontent));
+               boxcontent[0] = element_id;
+               RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                        "Write element_id box_reg(%4x) = %2x\n",
+                         box_reg, element_id);
+
+               switch (cmd_len) {
+               case 1:
+                       boxcontent[0] &= ~(BIT(7));
+                       memcpy((u8 *) (boxcontent) + 1,
+                              p_cmdbuffer, 1);
+
+                       for (idx = 0; idx < 4; idx++) {
+                               rtl_write_byte(rtlpriv, box_reg + idx,
+                                              boxcontent[idx]);
+                       }
+                       break;
+               case 2:
+                       boxcontent[0] &= ~(BIT(7));
+                       memcpy((u8 *) (boxcontent) + 1,
+                              p_cmdbuffer, 2);
+
+                       for (idx = 0; idx < 4; idx++) {
+                               rtl_write_byte(rtlpriv, box_reg + idx,
+                                              boxcontent[idx]);
+                       }
+                       break;
+               case 3:
+                       boxcontent[0] &= ~(BIT(7));
+                       memcpy((u8 *) (boxcontent) + 1,
+                              p_cmdbuffer, 3);
+
+                       for (idx = 0; idx < 4; idx++) {
+                               rtl_write_byte(rtlpriv, box_reg + idx,
+                                              boxcontent[idx]);
+                       }
+                       break;
+               case 4:
+                       boxcontent[0] |= (BIT(7));
+                       memcpy((u8 *) (boxextcontent),
+                              p_cmdbuffer, 2);
+                       memcpy((u8 *) (boxcontent) + 1,
+                              p_cmdbuffer + 2, 2);
+
+                       for (idx = 0; idx < 2; idx++) {
+                               rtl_write_byte(rtlpriv, box_extreg + idx,
+                                              boxextcontent[idx]);
+                       }
+
+                       for (idx = 0; idx < 4; idx++) {
+                               rtl_write_byte(rtlpriv, box_reg + idx,
+                                              boxcontent[idx]);
+                       }
+                       break;
+               case 5:
+                       boxcontent[0] |= (BIT(7));
+                       memcpy((u8 *) (boxextcontent),
+                              p_cmdbuffer, 2);
+                       memcpy((u8 *) (boxcontent) + 1,
+                              p_cmdbuffer + 2, 3);
+
+                       for (idx = 0; idx < 2; idx++) {
+                               rtl_write_byte(rtlpriv, box_extreg + idx,
+                                              boxextcontent[idx]);
+                       }
+
+                       for (idx = 0; idx < 4; idx++) {
+                               rtl_write_byte(rtlpriv, box_reg + idx,
+                                              boxcontent[idx]);
+                       }
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not process\n");
+                       break;
+               }
+
+               bwrite_sucess = true;
+
+               rtlhal->last_hmeboxnum = boxnum + 1;
+               if (rtlhal->last_hmeboxnum == 4)
+                       rtlhal->last_hmeboxnum = 0;
+
+               RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD,
+                        "pHalData->last_hmeboxnum  = %d\n",
+                        rtlhal->last_hmeboxnum);
+       }
+
+       spin_lock_irqsave(&rtlpriv->locks.h2c_lock, flag);
+       rtlhal->h2c_setinprogress = false;
+       spin_unlock_irqrestore(&rtlpriv->locks.h2c_lock, flag);
+
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_LOUD, "go out\n");
+}
+
+void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw,
+                           u8 element_id, u32 cmd_len, u8 *p_cmdbuffer)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+
+       if (rtlhal->fw_ready == false) {
+               RT_ASSERT(false,
+                        "return H2C cmd because of Fw download fail!!!\n");
+               return;
+       }
+
+       _rtl8723ae_fill_h2c_command(hw, element_id, cmd_len, p_cmdbuffer);
+       return;
+}
+
+void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw)
+{
+       u8 u1tmp;
+       u8 delay = 100;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtl_write_byte(rtlpriv, REG_HMETFR + 3, 0x20);
+       u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+
+       while (u1tmp & BIT(2)) {
+               delay--;
+               if (delay == 0)
+                       break;
+               udelay(50);
+               u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+       }
+       if (delay == 0) {
+               u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN + 1);
+               rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN + 1, u1tmp&(~BIT(2)));
+       }
+}
+
+void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 u1_h2c_set_pwrmode[3] = { 0 };
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD, "FW LPS mode = %d\n", mode);
+
+       SET_H2CCMD_PWRMODE_PARM_MODE(u1_h2c_set_pwrmode, mode);
+       SET_H2CCMD_PWRMODE_PARM_SMART_PS(u1_h2c_set_pwrmode, 1);
+       SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(u1_h2c_set_pwrmode,
+                                             ppsc->reg_max_lps_awakeintvl);
+
+       RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+                     "rtl8723ae_set_fw_rsvdpagepkt(): u1_h2c_set_pwrmode\n",
+                     u1_h2c_set_pwrmode, 3);
+       rtl8723ae_fill_h2c_cmd(hw, H2C_SETPWRMODE, 3, u1_h2c_set_pwrmode);
+
+}
+
+static bool _rtl8723ae_cmd_send_packet(struct ieee80211_hw *hw,
+                                      struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl8192_tx_ring *ring;
+       struct rtl_tx_desc *pdesc;
+       u8 own;
+       unsigned long flags;
+       struct sk_buff *pskb = NULL;
+
+       ring = &rtlpci->tx_ring[BEACON_QUEUE];
+
+       pskb = __skb_dequeue(&ring->queue);
+       if (pskb)
+               kfree_skb(pskb);
+
+       spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
+
+       pdesc = &ring->desc[0];
+       own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, true, HW_DESC_OWN);
+
+       rtlpriv->cfg->ops->fill_tx_cmddesc(hw, (u8 *) pdesc, 1, 1, skb);
+
+       __skb_queue_tail(&ring->queue, skb);
+
+       spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
+
+       rtlpriv->cfg->ops->tx_polling(hw, BEACON_QUEUE);
+
+       return true;
+}
+
+static u8 reserved_page_packet[TOTAL_RESERVED_PKT_LEN] = {
+       /* page 0 beacon */
+       0x80, 0x00, 0x00, 0x00, 0xFF, 0xFF, 0xFF, 0xFF,
+       0xFF, 0xFF, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+       0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x50, 0x08,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+       0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+       0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+       0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+       0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+       0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+       0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+       0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* page 1 beacon */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x10, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x10, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* page 2  ps-poll */
+       0xA4, 0x10, 0x01, 0xC0, 0x00, 0x40, 0x10, 0x10,
+       0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x18, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+       0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* page 3  null */
+       0x48, 0x01, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+       0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+       0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x72, 0x00, 0x20, 0x8C, 0x00, 0x12, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x80,
+       0x80, 0x01, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* page 4  probe_resp */
+       0x50, 0x00, 0x00, 0x00, 0x00, 0x40, 0x10, 0x10,
+       0x00, 0x03, 0x00, 0xE0, 0x4C, 0x76, 0x00, 0x42,
+       0x00, 0x40, 0x10, 0x10, 0x00, 0x03, 0x00, 0x00,
+       0x9E, 0x46, 0x15, 0x32, 0x27, 0xF2, 0x2D, 0x00,
+       0x64, 0x00, 0x00, 0x04, 0x00, 0x0C, 0x6C, 0x69,
+       0x6E, 0x6B, 0x73, 0x79, 0x73, 0x5F, 0x77, 0x6C,
+       0x61, 0x6E, 0x01, 0x04, 0x82, 0x84, 0x8B, 0x96,
+       0x03, 0x01, 0x01, 0x06, 0x02, 0x00, 0x00, 0x2A,
+       0x01, 0x00, 0x32, 0x08, 0x24, 0x30, 0x48, 0x6C,
+       0x0C, 0x12, 0x18, 0x60, 0x2D, 0x1A, 0x6C, 0x18,
+       0x03, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x3D, 0x00, 0xDD, 0x06, 0x00, 0xE0, 0x4C, 0x02,
+       0x01, 0x70, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+
+       /* page 5  probe_resp */
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+       0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00, 0x00,
+};
+
+void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool dl_finished)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct sk_buff *skb = NULL;
+
+       u32 totalpacketlen;
+       bool rtstatus;
+       u8 u1RsvdPageLoc[3] = { 0 };
+       bool dlok = false;
+
+       u8 *beacon;
+       u8 *p_pspoll;
+       u8 *nullfunc;
+       u8 *p_probersp;
+       /*---------------------------------------------------------
+                               (1) beacon
+       ---------------------------------------------------------
+       */
+       beacon = &reserved_page_packet[BEACON_PG * 128];
+       SET_80211_HDR_ADDRESS2(beacon, mac->mac_addr);
+       SET_80211_HDR_ADDRESS3(beacon, mac->bssid);
+
+       /*-------------------------------------------------------
+                               (2) ps-poll
+       --------------------------------------------------------
+       */
+       p_pspoll = &reserved_page_packet[PSPOLL_PG * 128];
+       SET_80211_PS_POLL_AID(p_pspoll, (mac->assoc_id | 0xc000));
+       SET_80211_PS_POLL_BSSID(p_pspoll, mac->bssid);
+       SET_80211_PS_POLL_TA(p_pspoll, mac->mac_addr);
+
+       SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(u1RsvdPageLoc, PSPOLL_PG);
+
+       /*--------------------------------------------------------
+                               (3) null data
+       ---------------------------------------------------------i
+       */
+       nullfunc = &reserved_page_packet[NULL_PG * 128];
+       SET_80211_HDR_ADDRESS1(nullfunc, mac->bssid);
+       SET_80211_HDR_ADDRESS2(nullfunc, mac->mac_addr);
+       SET_80211_HDR_ADDRESS3(nullfunc, mac->bssid);
+
+       SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(u1RsvdPageLoc, NULL_PG);
+
+       /*---------------------------------------------------------
+                               (4) probe response
+       ----------------------------------------------------------
+       */
+       p_probersp = &reserved_page_packet[PROBERSP_PG * 128];
+       SET_80211_HDR_ADDRESS1(p_probersp, mac->bssid);
+       SET_80211_HDR_ADDRESS2(p_probersp, mac->mac_addr);
+       SET_80211_HDR_ADDRESS3(p_probersp, mac->bssid);
+
+       SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(u1RsvdPageLoc, PROBERSP_PG);
+
+       totalpacketlen = TOTAL_RESERVED_PKT_LEN;
+
+       RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+                     "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+                     &reserved_page_packet[0], totalpacketlen);
+       RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+                     "rtl8723ae_set_fw_rsvdpagepkt(): HW_VAR_SET_TX_CMD: ALL\n",
+                     u1RsvdPageLoc, 3);
+
+       skb = dev_alloc_skb(totalpacketlen);
+       memcpy((u8 *) skb_put(skb, totalpacketlen),
+              &reserved_page_packet, totalpacketlen);
+
+       rtstatus = _rtl8723ae_cmd_send_packet(hw, skb);
+
+       if (rtstatus)
+               dlok = true;
+
+       if (dlok) {
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_LOUD,
+                        "Set RSVD page location to Fw.\n");
+               RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_DMESG,
+                               "H2C_RSVDPAGE:\n",
+                               u1RsvdPageLoc, 3);
+               rtl8723ae_fill_h2c_cmd(hw, H2C_RSVDPAGE,
+                                      sizeof(u1RsvdPageLoc), u1RsvdPageLoc);
+       } else
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "Set RSVD page location to Fw FAIL!!!!!!.\n");
+}
+
+void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus)
+{
+       u8 u1_joinbssrpt_parm[1] = { 0 };
+
+       SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(u1_joinbssrpt_parm, mstatus);
+
+       rtl8723ae_fill_h2c_cmd(hw, H2C_JOINBSSRPT, 1, u1_joinbssrpt_parm);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/fw.h
new file mode 100644 (file)
index 0000000..89994e1
--- /dev/null
@@ -0,0 +1,101 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ****************************************************************************
+ */
+
+#ifndef __RTL92C__FW__H__
+#define __RTL92C__FW__H__
+
+#define FW_8192C_START_ADDRESS                 0x1000
+#define FW_8192C_END_ADDRESS                   0x3FFF
+#define FW_8192C_PAGE_SIZE                     4096
+#define FW_8192C_POLLING_DELAY                 5
+#define FW_8192C_POLLING_TIMEOUT_COUNT         1000
+
+#define BEACON_PG                              0
+#define PSPOLL_PG                              2
+#define NULL_PG                                        3
+#define PROBERSP_PG                            4 /* ->5 */
+
+#define TOTAL_RESERVED_PKT_LEN                 768
+
+#define IS_FW_HEADER_EXIST(_pfwhdr)            \
+       ((_pfwhdr->signature&0xFF00) == 0x2300)
+
+struct rtl8723ae_firmware_header {
+       u16 signature;
+       u8 category;
+       u8 function;
+       u16 version;
+       u8 subversion;
+       u8 rsvd1;
+       u8 month;
+       u8 date;
+       u8 hour;
+       u8 minute;
+       u16 ramcodeSize;
+       u16 rsvd2;
+       u32 svnindex;
+       u32 rsvd3;
+       u32 rsvd4;
+       u32 rsvd5;
+};
+
+enum rtl8192c_h2c_cmd {
+       H2C_AP_OFFLOAD = 0,
+       H2C_SETPWRMODE = 1,
+       H2C_JOINBSSRPT = 2,
+       H2C_RSVDPAGE = 3,
+       H2C_RSSI_REPORT = 5,
+       H2C_RA_MASK = 6,
+       MAX_H2CCMD
+};
+
+#define SET_H2CCMD_PWRMODE_PARM_MODE(__ph2ccmd, __val)                 \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_SMART_PS(__ph2ccmd, __val)             \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_PWRMODE_PARM_BCN_PASS_TIME(__ph2ccmd, __val)        \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+#define SET_H2CCMD_JOINBSSRPT_PARM_OPMODE(__ph2ccmd, __val)            \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PROBE_RSP(__ph2ccmd, __val)            \
+       SET_BITS_TO_LE_1BYTE(__ph2ccmd, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_PSPOLL(__ph2ccmd, __val)               \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+1, 0, 8, __val)
+#define SET_H2CCMD_RSVDPAGE_LOC_NULL_DATA(__ph2ccmd, __val)            \
+       SET_BITS_TO_LE_1BYTE((__ph2ccmd)+2, 0, 8, __val)
+
+int rtl8723ae_download_fw(struct ieee80211_hw *hw);
+void rtl8723ae_fill_h2c_cmd(struct ieee80211_hw *hw, u8 element_id,
+                           u32 cmd_len, u8 *p_cmdbuffer);
+void rtl8723ae_firmware_selfreset(struct ieee80211_hw *hw);
+void rtl8723ae_set_fw_pwrmode_cmd(struct ieee80211_hw *hw, u8 mode);
+void rtl8723ae_set_fw_rsvdpagepkt(struct ieee80211_hw *hw, bool b_dl_finished);
+void rtl8723ae_set_fw_joinbss_report_cmd(struct ieee80211_hw *hw, u8 mstatus);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.c
new file mode 100644 (file)
index 0000000..3d092e4
--- /dev/null
@@ -0,0 +1,542 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "hal_bt_coexist.h"
+#include "../pci.h"
+#include "dm.h"
+#include "fw.h"
+#include "phy.h"
+#include "reg.h"
+#include "hal_btc.h"
+
+void rtl8723ae_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw,
+                                                bool reject)
+{
+}
+
+void _rtl8723_dm_bt_check_wifi_state(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       if (rtlpriv->link_info.busytraffic) {
+               rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_IDLE;
+
+               if (rtlpriv->link_info.tx_busy_traffic)
+                       rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_WIFI_UPLINK;
+               else
+                       rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_UPLINK;
+
+               if (rtlpriv->link_info.rx_busy_traffic)
+                       rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_WIFI_DOWNLINK;
+               else
+                       rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_DOWNLINK;
+       } else {
+               rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_WIFI_IDLE;
+               rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_UPLINK;
+               rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_DOWNLINK;
+       }
+
+       if (rtlpriv->mac80211.mode == WIRELESS_MODE_G ||
+           rtlpriv->mac80211.mode == WIRELESS_MODE_B) {
+               rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_WIFI_LEGACY;
+               rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_HT20;
+               rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_HT40;
+       } else {
+               rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_WIFI_LEGACY;
+               if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+                       rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_WIFI_HT40;
+                       rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_HT20;
+               } else {
+                       rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_WIFI_HT20;
+                       rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_HT40;
+               }
+       }
+
+       if (rtlpriv->bt_operation_on)
+               rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_BT30;
+       else
+               rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_BT30;
+}
+
+u8 rtl8723ae_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw,
+                                         u8 level_num, u8 rssi_thresh,
+                                         u8 rssi_thresh1)
+
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       long smooth;
+       u8 bt_rssi_state = 0;
+
+       smooth =  rtl8723ae_dm_bt_get_rx_ss(hw);
+
+       if (level_num == 2) {
+               rtlpcipriv->bt_coexist.cstate &=
+                               ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+
+               if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                   BT_RSSI_STATE_LOW) ||
+                   (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                   BT_RSSI_STATE_STAY_LOW)) {
+                       if (smooth >= (rssi_thresh +
+                           BT_FW_COEX_THRESH_TOL)) {
+                               bt_rssi_state = BT_RSSI_STATE_HIGH;
+                               rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state switch to High\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_LOW;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state stay at Low\n");
+                       }
+               } else {
+                       if (smooth < rssi_thresh) {
+                               bt_rssi_state = BT_RSSI_STATE_LOW;
+                               rtlpcipriv->bt_coexist.cstate |=
+                                        BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                        ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state switch to Low\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_HIGH;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state stay at High\n");
+                       }
+               }
+       } else if (level_num == 3) {
+               if (rssi_thresh > rssi_thresh1) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[DM][BT], RSSI_1 thresh error!!\n");
+                       return rtlpcipriv->bt_coexist.bt_pre_rssi_state;
+               }
+
+               if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                   BT_RSSI_STATE_LOW) ||
+                   (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                   BT_RSSI_STATE_STAY_LOW)) {
+                       if (smooth >=
+                           (rssi_thresh+BT_FW_COEX_THRESH_TOL)) {
+                               bt_rssi_state = BT_RSSI_STATE_MEDIUM;
+                               rtlpcipriv->bt_coexist.cstate |=
+                                        BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                        ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                        ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state switch to Medium\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_LOW;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state stay at Low\n");
+                       }
+               } else if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                          BT_RSSI_STATE_MEDIUM) ||
+                          (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                          BT_RSSI_STATE_STAY_MEDIUM)) {
+                       if (smooth >= (rssi_thresh1 +
+                           BT_FW_COEX_THRESH_TOL)) {
+                               bt_rssi_state = BT_RSSI_STATE_HIGH;
+                               rtlpcipriv->bt_coexist.cstate |=
+                                        BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                        ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                        ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state switch to High\n");
+                       } else if (smooth < rssi_thresh) {
+                               bt_rssi_state = BT_RSSI_STATE_LOW;
+                               rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state switch to Low\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_MEDIUM;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state stay at Medium\n");
+                       }
+               } else {
+                       if (smooth < rssi_thresh1) {
+                               bt_rssi_state = BT_RSSI_STATE_MEDIUM;
+                               rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_WIFI_RSSI_1_MEDIUM;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_RSSI_1_HIGH;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_RSSI_1_LOW;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state switch to Medium\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_HIGH;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI_1 state stay at High\n");
+                       }
+               }
+       }
+
+       rtlpcipriv->bt_coexist.bt_pre_rssi_state1 = bt_rssi_state;
+
+       return bt_rssi_state;
+}
+
+u8 rtl8723ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw,
+                                        u8 level_num, u8 rssi_thresh,
+                                        u8 rssi_thresh1)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       long smooth;
+       u8 bt_rssi_state = 0;
+
+       smooth = rtl8723ae_dm_bt_get_rx_ss(hw);
+
+       if (level_num == 2) {
+               rtlpcipriv->bt_coexist.cstate &=
+                                        ~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+
+               if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                   BT_RSSI_STATE_LOW) ||
+                   (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                   BT_RSSI_STATE_STAY_LOW)){
+                       if (smooth >=
+                           (rssi_thresh + BT_FW_COEX_THRESH_TOL)) {
+                               bt_rssi_state = BT_RSSI_STATE_HIGH;
+                               rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_RSSI_LOW;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state switch to High\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_LOW;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state stay at Low\n");
+                       }
+               } else {
+                       if (smooth < rssi_thresh) {
+                               bt_rssi_state = BT_RSSI_STATE_LOW;
+                               rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_WIFI_RSSI_LOW;
+                               rtlpcipriv->bt_coexist.cstate &=
+                                       ~BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state switch to Low\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_HIGH;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state stay at High\n");
+                       }
+               }
+       } else if (level_num == 3) {
+               if (rssi_thresh > rssi_thresh1) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[DM][BT], RSSI thresh error!!\n");
+                       return rtlpcipriv->bt_coexist.bt_pre_rssi_state;
+               }
+               if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                   BT_RSSI_STATE_LOW) ||
+                   (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                   BT_RSSI_STATE_STAY_LOW)) {
+                       if (smooth >=
+                           (rssi_thresh + BT_FW_COEX_THRESH_TOL)) {
+                               bt_rssi_state = BT_RSSI_STATE_MEDIUM;
+                               rtlpcipriv->bt_coexist.cstate
+                                       |= BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+                               rtlpcipriv->bt_coexist.cstate
+                                       &= ~BT_COEX_STATE_WIFI_RSSI_LOW;
+                               rtlpcipriv->bt_coexist.cstate
+                                       &= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state switch to Medium\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_LOW;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state stay at Low\n");
+                       }
+               } else if ((rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                          BT_RSSI_STATE_MEDIUM) ||
+                          (rtlpcipriv->bt_coexist.bt_pre_rssi_state ==
+                          BT_RSSI_STATE_STAY_MEDIUM)) {
+                       if (smooth >=
+                           (rssi_thresh1 + BT_FW_COEX_THRESH_TOL)) {
+                               bt_rssi_state = BT_RSSI_STATE_HIGH;
+                               rtlpcipriv->bt_coexist.cstate
+                                       |= BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               rtlpcipriv->bt_coexist.cstate
+                                       &= ~BT_COEX_STATE_WIFI_RSSI_LOW;
+                               rtlpcipriv->bt_coexist.cstate
+                                       &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state switch to High\n");
+                       } else if (smooth < rssi_thresh) {
+                               bt_rssi_state = BT_RSSI_STATE_LOW;
+                               rtlpcipriv->bt_coexist.cstate
+                                       |= BT_COEX_STATE_WIFI_RSSI_LOW;
+                               rtlpcipriv->bt_coexist.cstate
+                                       &= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               rtlpcipriv->bt_coexist.cstate
+                                       &= ~BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state switch to Low\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_MEDIUM;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state stay at Medium\n");
+                       }
+               } else {
+                       if (smooth < rssi_thresh1) {
+                               bt_rssi_state = BT_RSSI_STATE_MEDIUM;
+                               rtlpcipriv->bt_coexist.cstate
+                                       |= BT_COEX_STATE_WIFI_RSSI_MEDIUM;
+                               rtlpcipriv->bt_coexist.cstate
+                                       &= ~BT_COEX_STATE_WIFI_RSSI_HIGH;
+                               rtlpcipriv->bt_coexist.cstate
+                                       &= ~BT_COEX_STATE_WIFI_RSSI_LOW;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state switch to Medium\n");
+                       } else {
+                               bt_rssi_state = BT_RSSI_STATE_STAY_HIGH;
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                        "[DM][BT], RSSI state stay at High\n");
+                       }
+               }
+       }
+
+       rtlpcipriv->bt_coexist.bt_pre_rssi_state = bt_rssi_state;
+       return bt_rssi_state;
+}
+
+long rtl8723ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       long smooth = 0;
+
+       if (rtlpriv->mac80211.link_state >= MAC80211_LINKED)
+               smooth = GET_UNDECORATED_AVERAGE_RSSI(rtlpriv);
+       else
+               smooth = rtlpriv->dm.entry_min_undec_sm_pwdb;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "rtl8723ae_dm_bt_get_rx_ss() = %ld\n", smooth);
+
+       return smooth;
+}
+
+void rtl8723ae_dm_bt_balance(struct ieee80211_hw *hw,
+                            bool balance_on, u8 ms0, u8 ms1)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 h2c_parameter[3] = {0};
+
+       if (balance_on) {
+               h2c_parameter[2] = 1;
+               h2c_parameter[1] = ms1;
+               h2c_parameter[0] = ms0;
+               rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+       } else {
+               h2c_parameter[2] = 0;
+               h2c_parameter[1] = 0;
+               h2c_parameter[0] = 0;
+       }
+       rtlpcipriv->bt_coexist.balance_on = balance_on;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[DM][BT], Balance=[%s:%dms:%dms], write 0xc=0x%x\n",
+                balance_on ? "ON" : "OFF", ms0, ms1,
+                h2c_parameter[0]<<16 | h2c_parameter[1]<<8 | h2c_parameter[2]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0xc, 3, h2c_parameter);
+}
+
+
+void rtl8723ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       if (type == BT_AGCTABLE_OFF) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BT]AGCTable Off!\n");
+               rtl_write_dword(rtlpriv, 0xc78, 0x641c0001);
+               rtl_write_dword(rtlpriv, 0xc78, 0x631d0001);
+               rtl_write_dword(rtlpriv, 0xc78, 0x621e0001);
+               rtl_write_dword(rtlpriv, 0xc78, 0x611f0001);
+               rtl_write_dword(rtlpriv, 0xc78, 0x60200001);
+
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_AGC_HP, 0xfffff, 0x32000);
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_AGC_HP, 0xfffff, 0x71000);
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_AGC_HP, 0xfffff, 0xb0000);
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_AGC_HP, 0xfffff, 0xfc000);
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_G1, 0xfffff, 0x30355);
+       } else if (type == BT_AGCTABLE_ON) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BT]AGCTable On!\n");
+               rtl_write_dword(rtlpriv, 0xc78, 0x4e1c0001);
+               rtl_write_dword(rtlpriv, 0xc78, 0x4d1d0001);
+               rtl_write_dword(rtlpriv, 0xc78, 0x4c1e0001);
+               rtl_write_dword(rtlpriv, 0xc78, 0x4b1f0001);
+               rtl_write_dword(rtlpriv, 0xc78, 0x4a200001);
+
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_AGC_HP, 0xfffff, 0xdc000);
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_AGC_HP, 0xfffff, 0x90000);
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_AGC_HP, 0xfffff, 0x51000);
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_AGC_HP, 0xfffff, 0x12000);
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A,
+                                       RF_RX_G1, 0xfffff, 0x00355);
+
+               rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+       }
+}
+
+void rtl8723ae_dm_bt_bback_off_level(struct ieee80211_hw *hw, u8 type)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       if (type == BT_BB_BACKOFF_OFF) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BT]BBBackOffLevel Off!\n");
+               rtl_write_dword(rtlpriv, 0xc04, 0x3a05611);
+       } else if (type == BT_BB_BACKOFF_ON) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BT]BBBackOffLevel On!\n");
+               rtl_write_dword(rtlpriv, 0xc04, 0x3a07611);
+               rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+       }
+}
+
+void rtl8723ae_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "rtl8723ae_dm_bt_fw_coex_all_off()\n");
+
+       if (rtlpcipriv->bt_coexist.fw_coexist_all_off)
+               return;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "rtl8723ae_dm_bt_fw_coex_all_off(), real Do\n");
+       rtl8723ae_dm_bt_fw_coex_all_off_8723a(hw);
+       rtlpcipriv->bt_coexist.fw_coexist_all_off = true;
+}
+
+void rtl8723ae_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "rtl8723ae_dm_bt_sw_coex_all_off()\n");
+
+       if (rtlpcipriv->bt_coexist.sw_coexist_all_off)
+               return;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "rtl8723ae_dm_bt_sw_coex_all_off(), real Do\n");
+       rtl8723ae_dm_bt_sw_coex_all_off_8723a(hw);
+       rtlpcipriv->bt_coexist.sw_coexist_all_off = true;
+}
+
+void rtl8723ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "rtl8723ae_dm_bt_hw_coex_all_off()\n");
+
+       if (rtlpcipriv->bt_coexist.hw_coexist_all_off)
+               return;
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "rtl8723ae_dm_bt_hw_coex_all_off(), real Do\n");
+
+       rtl8723ae_dm_bt_hw_coex_all_off_8723a(hw);
+
+       rtlpcipriv->bt_coexist.hw_coexist_all_off = true;
+}
+
+void rtl8723ae_btdm_coex_all_off(struct ieee80211_hw *hw)
+{
+       rtl8723ae_dm_bt_fw_coex_all_off(hw);
+       rtl8723ae_dm_bt_sw_coex_all_off(hw);
+       rtl8723ae_dm_bt_hw_coex_all_off(hw);
+}
+
+bool rtl8723ae_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       if ((rtlpcipriv->bt_coexist.previous_state ==
+           rtlpcipriv->bt_coexist.cstate) &&
+           (rtlpcipriv->bt_coexist.previous_state_h ==
+           rtlpcipriv->bt_coexist.cstate_h))
+               return false;
+       else
+               return true;
+}
+
+bool rtl8723ae_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->link_info.tx_busy_traffic)
+               return true;
+       else
+               return false;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_bt_coexist.h
new file mode 100644 (file)
index 0000000..76f4d12
--- /dev/null
@@ -0,0 +1,160 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_HAL_BT_COEXIST_H__
+#define __RTL8723E_HAL_BT_COEXIST_H__
+
+#include "../wifi.h"
+
+/* The reg define is for 8723 */
+#define        REG_HIGH_PRIORITY_TXRX                  0x770
+#define        REG_LOW_PRIORITY_TXRX                   0x774
+
+#define BT_FW_COEX_THRESH_TOL                  6
+#define BT_FW_COEX_THRESH_20                   20
+#define BT_FW_COEX_THRESH_23                   23
+#define BT_FW_COEX_THRESH_25                   25
+#define BT_FW_COEX_THRESH_30                   30
+#define BT_FW_COEX_THRESH_35                   35
+#define BT_FW_COEX_THRESH_40                   40
+#define BT_FW_COEX_THRESH_45                   45
+#define BT_FW_COEX_THRESH_47                   47
+#define BT_FW_COEX_THRESH_50                   50
+#define BT_FW_COEX_THRESH_55                   55
+
+#define BT_COEX_STATE_BT30                     BIT(0)
+#define BT_COEX_STATE_WIFI_HT20                        BIT(1)
+#define BT_COEX_STATE_WIFI_HT40                        BIT(2)
+#define BT_COEX_STATE_WIFI_LEGACY              BIT(3)
+
+#define BT_COEX_STATE_WIFI_RSSI_LOW            BIT(4)
+#define BT_COEX_STATE_WIFI_RSSI_MEDIUM         BIT(5)
+#define BT_COEX_STATE_WIFI_RSSI_HIGH           BIT(6)
+#define BT_COEX_STATE_DEC_BT_POWER             BIT(7)
+
+#define BT_COEX_STATE_WIFI_IDLE                        BIT(8)
+#define BT_COEX_STATE_WIFI_UPLINK              BIT(9)
+#define BT_COEX_STATE_WIFI_DOWNLINK            BIT(10)
+
+#define BT_COEX_STATE_BT_INQ_PAGE              BIT(11)
+#define BT_COEX_STATE_BT_IDLE                  BIT(12)
+#define BT_COEX_STATE_BT_UPLINK                        BIT(13)
+#define BT_COEX_STATE_BT_DOWNLINK              BIT(14)
+
+#define BT_COEX_STATE_HOLD_FOR_BT_OPERATION    BIT(15)
+#define BT_COEX_STATE_BT_RSSI_LOW              BIT(19)
+
+#define BT_COEX_STATE_PROFILE_HID              BIT(20)
+#define BT_COEX_STATE_PROFILE_A2DP             BIT(21)
+#define BT_COEX_STATE_PROFILE_PAN              BIT(22)
+#define BT_COEX_STATE_PROFILE_SCO              BIT(23)
+
+#define BT_COEX_STATE_WIFI_RSSI_1_LOW          BIT(24)
+#define BT_COEX_STATE_WIFI_RSSI_1_MEDIUM       BIT(25)
+#define BT_COEX_STATE_WIFI_RSSI_1_HIGH         BIT(26)
+
+#define BT_COEX_STATE_BTINFO_COMMON            BIT(30)
+#define BT_COEX_STATE_BTINFO_B_HID_SCOESCO     BIT(31)
+#define BT_COEX_STATE_BTINFO_B_FTP_A2DP                BIT(29)
+
+#define BT_COEX_STATE_BT_CNT_LEVEL_0           BIT(0)
+#define BT_COEX_STATE_BT_CNT_LEVEL_1           BIT(1)
+#define BT_COEX_STATE_BT_CNT_LEVEL_2           BIT(2)
+#define BT_COEX_STATE_BT_CNT_LEVEL_3           BIT(3)
+
+#define BT_RSSI_STATE_HIGH                     0
+#define BT_RSSI_STATE_MEDIUM                   1
+#define BT_RSSI_STATE_LOW                      2
+#define BT_RSSI_STATE_STAY_HIGH                        3
+#define BT_RSSI_STATE_STAY_MEDIUM              4
+#define BT_RSSI_STATE_STAY_LOW                 5
+
+#define        BT_AGCTABLE_OFF                         0
+#define        BT_AGCTABLE_ON                          1
+#define        BT_BB_BACKOFF_OFF                       0
+#define        BT_BB_BACKOFF_ON                        1
+#define        BT_FW_NAV_OFF                           0
+#define        BT_FW_NAV_ON                            1
+
+#define        BT_COEX_MECH_NONE                       0
+#define        BT_COEX_MECH_SCO                        1
+#define        BT_COEX_MECH_HID                        2
+#define        BT_COEX_MECH_A2DP                       3
+#define        BT_COEX_MECH_PAN                        4
+#define        BT_COEX_MECH_HID_A2DP                   5
+#define        BT_COEX_MECH_HID_PAN                    6
+#define        BT_COEX_MECH_PAN_A2DP                   7
+#define        BT_COEX_MECH_HID_SCO_ESCO               8
+#define        BT_COEX_MECH_FTP_A2DP                   9
+#define        BT_COEX_MECH_COMMON                     10
+#define        BT_COEX_MECH_MAX                        11
+
+#define        BT_DBG_PROFILE_NONE                     0
+#define        BT_DBG_PROFILE_SCO                      1
+#define        BT_DBG_PROFILE_HID                      2
+#define        BT_DBG_PROFILE_A2DP                     3
+#define        BT_DBG_PROFILE_PAN                      4
+#define        BT_DBG_PROFILE_HID_A2DP                 5
+#define        BT_DBG_PROFILE_HID_PAN                  6
+#define        BT_DBG_PROFILE_PAN_A2DP                 7
+#define        BT_DBG_PROFILE_MAX                      9
+
+#define        BTINFO_B_FTP                            BIT(7)
+#define        BTINFO_B_A2DP                           BIT(6)
+#define        BTINFO_B_HID                            BIT(5)
+#define        BTINFO_B_SCO_BUSY                       BIT(4)
+#define        BTINFO_B_ACL_BUSY                       BIT(3)
+#define        BTINFO_B_INQ_PAGE                       BIT(2)
+#define        BTINFO_B_SCO_ESCO                       BIT(1)
+#define        BTINFO_B_CONNECTION                     BIT(0)
+
+
+void rtl8723ae_btdm_coex_all_off(struct ieee80211_hw *hw);
+void rtl8723ae_dm_bt_fw_coex_all_off(struct ieee80211_hw *hw);
+
+void rtl8723ae_dm_bt_sw_coex_all_off(struct ieee80211_hw *hw);
+void rtl8723ae_dm_bt_hw_coex_all_off(struct ieee80211_hw *hw);
+long rtl8723ae_dm_bt_get_rx_ss(struct ieee80211_hw *hw);
+void rtl8723ae_dm_bt_balance(struct ieee80211_hw *hw,
+                           bool balance_on, u8 ms0, u8 ms1);
+void rtl8723ae_dm_bt_agc_table(struct ieee80211_hw *hw, u8 type);
+void rtl8723ae_dm_bt_bback_off_level(struct ieee80211_hw *hw, u8 type);
+u8 rtl8723ae_dm_bt_check_coex_rssi_state(struct ieee80211_hw *hw,
+                                       u8 level_num, u8 rssi_thresh,
+                                       u8 rssi_thresh1);
+u8 rtl8723ae_dm_bt_check_coex_rssi_state1(struct ieee80211_hw *hw,
+                                        u8  level_num, u8 rssi_thresh,
+                                        u8 rssi_thresh1);
+void _rtl8723_dm_bt_check_wifi_state(struct ieee80211_hw *hw);
+void rtl8723ae_dm_bt_reject_ap_aggregated_packet(struct ieee80211_hw *hw,
+                                               bool reject);
+
+bool rtl8723ae_dm_bt_is_coexist_state_changed(struct ieee80211_hw *hw);
+bool rtl8723ae_dm_bt_is_wifi_up_link(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.c
new file mode 100644 (file)
index 0000000..887d521
--- /dev/null
@@ -0,0 +1,1786 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ****************************************************************************
+ */
+#include "hal_btc.h"
+#include "../pci.h"
+#include "phy.h"
+#include "fw.h"
+#include "reg.h"
+#include "def.h"
+
+void rtl8723ae_bt_coex_off_before_lps(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       if (!rtlpcipriv->bt_coexist.bt_coexistence)
+               return;
+
+       if (ppsc->inactiveps) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BT][DM], Before enter IPS, turn off all Coexist DM\n");
+               rtlpcipriv->bt_coexist.cstate = 0;
+               rtlpcipriv->bt_coexist.previous_state = 0;
+               rtlpcipriv->bt_coexist.cstate_h = 0;
+               rtlpcipriv->bt_coexist.previous_state_h = 0;
+               rtl8723ae_btdm_coex_all_off(hw);
+       }
+}
+
+static enum _RT_MEDIA_STATUS mgnt_link_status_query(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       enum _RT_MEDIA_STATUS m_status = RT_MEDIA_DISCONNECT;
+
+       u8 bibss = (mac->opmode == NL80211_IFTYPE_ADHOC) ? 1 : 0;
+
+       if (bibss || rtlpriv->mac80211.link_state >= MAC80211_LINKED)
+               m_status = RT_MEDIA_CONNECT;
+
+       return m_status;
+}
+
+void rtl_8723e_bt_wifi_media_status_notify(struct ieee80211_hw *hw,
+                                          bool mstatus)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 h2c_parameter[3] = {0};
+       u8 chnl;
+
+       if (!rtlpcipriv->bt_coexist.bt_coexistence)
+               return;
+
+       if (RT_MEDIA_CONNECT == mstatus)
+               h2c_parameter[0] = 0x1; /* 0: disconnected, 1:connected */
+       else
+               h2c_parameter[0] = 0x0;
+
+       if (mgnt_link_status_query(hw)) {
+               chnl = rtlphy->current_channel;
+               h2c_parameter[1] = chnl;
+       }
+
+       if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40)
+               h2c_parameter[2] = 0x30;
+       else
+               h2c_parameter[2] = 0x20;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "[BTCoex], FW write 0x19 = 0x%x\n",
+                h2c_parameter[0]<<16|h2c_parameter[1]<<8|h2c_parameter[2]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0x19, 3, h2c_parameter);
+
+}
+
+static bool rtl8723ae_dm_bt_is_wifi_busy(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       if (rtlpriv->link_info.busytraffic ||
+               rtlpriv->link_info.rx_busy_traffic ||
+               rtlpriv->link_info.tx_busy_traffic)
+               return true;
+       else
+               return false;
+}
+
+static void rtl8723ae_dm_bt_set_fw_3a(struct ieee80211_hw *hw,
+                                     u8 byte1, u8 byte2, u8 byte3,
+                                     u8 byte4, u8 byte5)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 h2c_parameter[5] = {0};
+
+       h2c_parameter[0] = byte1;
+       h2c_parameter[1] = byte2;
+       h2c_parameter[2] = byte3;
+       h2c_parameter[3] = byte4;
+       h2c_parameter[4] = byte5;
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], FW write 0x3a(4bytes) = 0x%x%8x\n",
+                h2c_parameter[0], h2c_parameter[1]<<24 | h2c_parameter[2]<<16 |
+                h2c_parameter[3]<<8 | h2c_parameter[4]);
+       rtl8723ae_fill_h2c_cmd(hw, 0x3a, 5, h2c_parameter);
+}
+
+static bool rtl8723ae_dm_bt_need_to_dec_bt_pwr(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (mgnt_link_status_query(hw) == RT_MEDIA_CONNECT) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "Need to decrease bt power\n");
+               rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_DEC_BT_POWER;
+               return true;
+       }
+
+       rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_DEC_BT_POWER;
+       return false;
+}
+
+static bool rtl8723ae_dm_bt_is_same_coexist_state(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       if ((rtlpcipriv->bt_coexist.previous_state ==
+           rtlpcipriv->bt_coexist.cstate) &&
+           (rtlpcipriv->bt_coexist.previous_state_h ==
+           rtlpcipriv->bt_coexist.cstate_h)) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[DM][BT], Coexist state do not chang!!\n");
+               return true;
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[DM][BT], Coexist state changed!!\n");
+               return false;
+       }
+}
+
+static void rtl8723ae_dm_bt_set_coex_table(struct ieee80211_hw *hw,
+                                          u32 val_0x6c0, u32 val_0x6c8,
+                                          u32 val_0x6cc)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "set coex table, set 0x6c0 = 0x%x\n", val_0x6c0);
+       rtl_write_dword(rtlpriv, 0x6c0, val_0x6c0);
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "set coex table, set 0x6c8 = 0x%x\n", val_0x6c8);
+       rtl_write_dword(rtlpriv, 0x6c8, val_0x6c8);
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "set coex table, set 0x6cc = 0x%x\n", val_0x6cc);
+       rtl_write_byte(rtlpriv, 0x6cc, val_0x6cc);
+}
+
+static void rtl8723ae_dm_bt_set_hw_pta_mode(struct ieee80211_hw *hw, bool mode)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (BT_PTA_MODE_ON == mode) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "PTA mode on, ");
+               /*  Enable GPIO 0/1/2/3/8 pins for bt */
+               rtl_write_byte(rtlpriv, 0x40, 0x20);
+               rtlpcipriv->bt_coexist.hw_coexist_all_off = false;
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE, "PTA mode off\n");
+               rtl_write_byte(rtlpriv, 0x40, 0x0);
+       }
+}
+
+static void rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(struct ieee80211_hw *hw,
+                                                   u8 type)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (BT_RF_RX_LPF_CORNER_SHRINK == type) {
+               /* Shrink RF Rx LPF corner, 0x1e[7:4]=1111 ==> [11:4] by Jenyu*/
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "Shrink RF Rx LPF corner!!\n");
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e, 0xfffff,
+                                       0xf0ff7);
+               rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+       } else if (BT_RF_RX_LPF_CORNER_RESUME == type) {
+               /*Resume RF Rx LPF corner*/
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "Resume RF Rx LPF corner!!\n");
+               rtl8723ae_phy_set_rf_reg(hw, RF90_PATH_A, 0x1e, 0xfffff,
+                       rtlpcipriv->bt_coexist.bt_rfreg_origin_1e);
+       }
+}
+
+static void rtl8723ae_bt_set_penalty_tx_rate_adap(struct ieee80211_hw *hw,
+                                                 u8 ra_type)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       u8 tmu1;
+
+       tmu1 = rtl_read_byte(rtlpriv, 0x4fd);
+       tmu1 |= BIT(0);
+       if (BT_TX_RATE_ADAPTIVE_LOW_PENALTY == ra_type) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "Tx rate adaptive, set low penalty!!\n");
+               tmu1 &= ~BIT(2);
+               rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+       } else if (BT_TX_RATE_ADAPTIVE_NORMAL == ra_type) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "Tx rate adaptive, set normal!!\n");
+               tmu1 |= BIT(2);
+       }
+       rtl_write_byte(rtlpriv, 0x4fd, tmu1);
+}
+
+static void rtl8723ae_dm_bt_btdm_structure_reload(struct ieee80211_hw *hw,
+                                                struct btdm_8723 *btdm)
+{
+       btdm->all_off = false;
+       btdm->agc_table_en = false;
+       btdm->adc_back_off_on = false;
+       btdm->b2_ant_hid_en = false;
+       btdm->low_penalty_rate_adaptive = false;
+       btdm->rf_rx_lpf_shrink = false;
+       btdm->reject_aggre_pkt = false;
+
+       btdm->tdma_on = false;
+       btdm->tdma_ant = TDMA_2ANT;
+       btdm->tdma_nav = TDMA_NAV_OFF;
+       btdm->tdma_dac_swing = TDMA_DAC_SWING_OFF;
+       btdm->fw_dac_swing_lvl = 0x20;
+
+       btdm->tra_tdma_on = false;
+       btdm->tra_tdma_ant = TDMA_2ANT;
+       btdm->tra_tdma_nav = TDMA_NAV_OFF;
+       btdm->ignore_wlan_act = false;
+
+       btdm->ps_tdma_on = false;
+       btdm->ps_tdma_byte[0] = 0x0;
+       btdm->ps_tdma_byte[1] = 0x0;
+       btdm->ps_tdma_byte[2] = 0x0;
+       btdm->ps_tdma_byte[3] = 0x8;
+       btdm->ps_tdma_byte[4] = 0x0;
+
+       btdm->pta_on = true;
+       btdm->val_0x6c0 = 0x5a5aaaaa;
+       btdm->val_0x6c8 = 0xcc;
+       btdm->val_0x6cc = 0x3;
+
+       btdm->sw_dac_swing_on = false;
+       btdm->sw_dac_swing_lvl = 0xc0;
+       btdm->wlan_act_hi = 0x20;
+       btdm->wlan_act_lo = 0x10;
+       btdm->bt_retry_index = 2;
+
+       btdm->dec_bt_pwr = false;
+}
+
+static void dm_bt_btdm_structure_reload_all_off(struct ieee80211_hw *hw,
+                                               struct btdm_8723 *btdm)
+{
+       rtl8723ae_dm_bt_btdm_structure_reload(hw, btdm);
+       btdm->all_off = true;
+       btdm->pta_on = false;
+       btdm->wlan_act_hi = 0x10;
+}
+
+static bool rtl8723ae_dm_bt_is_2_ant_common_action(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct btdm_8723 btdm8723;
+       bool common = false;
+
+       rtl8723ae_dm_bt_btdm_structure_reload(hw, &btdm8723);
+
+       if (!rtl8723ae_dm_bt_is_wifi_busy(hw)
+           && !rtlpcipriv->bt_coexist.bt_busy) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "Wifi idle + Bt idle, bt coex mechanism always off!!\n");
+               dm_bt_btdm_structure_reload_all_off(hw, &btdm8723);
+               common = true;
+       } else if (rtl8723ae_dm_bt_is_wifi_busy(hw)
+                  && !rtlpcipriv->bt_coexist.bt_busy) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "Wifi non-idle + Bt disabled/idle!!\n");
+               btdm8723.low_penalty_rate_adaptive = true;
+               btdm8723.rf_rx_lpf_shrink = false;
+               btdm8723.reject_aggre_pkt = false;
+
+               /* sw mechanism */
+               btdm8723.agc_table_en = false;
+               btdm8723.adc_back_off_on = false;
+               btdm8723.sw_dac_swing_on = false;
+
+               btdm8723.pta_on = true;
+               btdm8723.val_0x6c0 = 0x5a5aaaaa;
+               btdm8723.val_0x6c8 = 0xcccc;
+               btdm8723.val_0x6cc = 0x3;
+
+               btdm8723.tdma_on = false;
+               btdm8723.tdma_dac_swing = TDMA_DAC_SWING_OFF;
+               btdm8723.b2_ant_hid_en = false;
+
+               common = true;
+       } else if (rtlpcipriv->bt_coexist.bt_busy) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "Bt non-idle!\n");
+               if (mgnt_link_status_query(hw) == RT_MEDIA_CONNECT) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi connection exist\n");
+                       common = false;
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "No Wifi connection!\n");
+                       btdm8723.rf_rx_lpf_shrink = true;
+                       btdm8723.low_penalty_rate_adaptive = false;
+                       btdm8723.reject_aggre_pkt = false;
+
+                       /* sw mechanism */
+                       btdm8723.agc_table_en = false;
+                       btdm8723.adc_back_off_on = false;
+                       btdm8723.sw_dac_swing_on = false;
+
+                       btdm8723.pta_on = true;
+                       btdm8723.val_0x6c0 = 0x55555555;
+                       btdm8723.val_0x6c8 = 0x0000ffff;
+                       btdm8723.val_0x6cc = 0x3;
+
+                       btdm8723.tdma_on = false;
+                       btdm8723.tdma_dac_swing = TDMA_DAC_SWING_OFF;
+                       btdm8723.b2_ant_hid_en = false;
+
+                       common = true;
+               }
+       }
+
+       if (rtl8723ae_dm_bt_need_to_dec_bt_pwr(hw))
+               btdm8723.dec_bt_pwr = true;
+
+       if (common)
+               rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_BTINFO_COMMON;
+
+       if (common && rtl8723ae_dm_bt_is_coexist_state_changed(hw))
+               rtl8723ae_dm_bt_set_bt_dm(hw, &btdm8723);
+
+       return common;
+}
+
+static void rtl8723ae_dm_bt_set_sw_full_time_dac_swing(struct ieee80211_hw *hw,
+                                                      bool sw_dac_swing_on,
+                                                      u32 sw_dac_swing_lvl)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (sw_dac_swing_on) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], SwDacSwing = 0x%x\n", sw_dac_swing_lvl);
+               rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000,
+                                        sw_dac_swing_lvl);
+               rtlpcipriv->bt_coexist.sw_coexist_all_off = false;
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], SwDacSwing Off!\n");
+               rtl8723ae_phy_set_bb_reg(hw, 0x880, 0xff000000, 0xc0);
+       }
+}
+
+static void rtl8723ae_dm_bt_set_fw_dec_bt_pwr(struct ieee80211_hw *hw,
+                                             bool dec_bt_pwr)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 h2c_parameter[1] = {0};
+
+       h2c_parameter[0] = 0;
+
+       if (dec_bt_pwr) {
+               h2c_parameter[0] |= BIT(1);
+               rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+       }
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], decrease Bt Power : %s, write 0x21 = 0x%x\n",
+                (dec_bt_pwr ? "Yes!!" : "No!!"), h2c_parameter[0]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0x21, 1, h2c_parameter);
+}
+
+static void rtl8723ae_dm_bt_set_fw_2_ant_hid(struct ieee80211_hw *hw,
+                                           bool enable, bool dac_swing_on)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 h2c_parameter[1] = {0};
+
+       if (enable) {
+               h2c_parameter[0] |= BIT(0);
+               rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+       }
+       if (dac_swing_on)
+               h2c_parameter[0] |= BIT(1); /* Dac Swing default enable */
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], turn 2-Ant+HID mode %s, DACSwing:%s, write 0x15 = 0x%x\n",
+                (enable ? "ON!!" : "OFF!!"), (dac_swing_on ? "ON" : "OFF"),
+                h2c_parameter[0]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0x15, 1, h2c_parameter);
+}
+
+static void rtl8723ae_dm_bt_set_fw_tdma_ctrl(struct ieee80211_hw *hw,
+                                            bool enable, u8 ant_num, u8 nav_en,
+                                            u8 dac_swing_en)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       u8 h2c_parameter[1] = {0};
+       u8 h2c_parameter1[1] = {0};
+
+       h2c_parameter[0] = 0;
+       h2c_parameter1[0] = 0;
+
+       if (enable) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], set BT PTA update manager to trigger update!!\n");
+               h2c_parameter1[0] |= BIT(0);
+
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], turn TDMA mode ON!!\n");
+               h2c_parameter[0] |= BIT(0);             /* function enable */
+               if (TDMA_1ANT == ant_num) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TDMA_1ANT\n");
+                       h2c_parameter[0] |= BIT(1);
+               } else if (TDMA_2ANT == ant_num) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TDMA_2ANT\n");
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], Unknown Ant\n");
+               }
+
+               if (TDMA_NAV_OFF == nav_en) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TDMA_NAV_OFF\n");
+               } else if (TDMA_NAV_ON == nav_en) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TDMA_NAV_ON\n");
+                       h2c_parameter[0] |= BIT(2);
+               }
+
+               if (TDMA_DAC_SWING_OFF == dac_swing_en) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TDMA_DAC_SWING_OFF\n");
+               } else if (TDMA_DAC_SWING_ON == dac_swing_en) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TDMA_DAC_SWING_ON\n");
+                       h2c_parameter[0] |= BIT(4);
+               }
+               rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], set BT PTA update manager to no update!!\n");
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], turn TDMA mode OFF!!\n");
+       }
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], FW2AntTDMA, write 0x26 = 0x%x\n",
+                h2c_parameter1[0]);
+       rtl8723ae_fill_h2c_cmd(hw, 0x26, 1, h2c_parameter1);
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], FW2AntTDMA, write 0x14 = 0x%x\n", h2c_parameter[0]);
+       rtl8723ae_fill_h2c_cmd(hw, 0x14, 1, h2c_parameter);
+}
+
+static void rtl8723ae_dm_bt_set_fw_ignore_wlan_act(struct ieee80211_hw *hw,
+                                                  bool enable)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       u8 h2c_parameter[1] = {0};
+
+       if (enable) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], BT Ignore Wlan_Act !!\n");
+               h2c_parameter[0] |= BIT(0);             /* function enable */
+               rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], BT don't ignore Wlan_Act !!\n");
+       }
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], set FW for BT Ignore Wlan_Act, write 0x25 = 0x%x\n",
+                h2c_parameter[0]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0x25, 1, h2c_parameter);
+}
+
+static void rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(struct ieee80211_hw *hw,
+                                                bool enable, u8 ant_num,
+                                                u8 nav_en)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 h2c_parameter[2] = {0};
+
+       /* Only 8723 B cut should do this */
+       if (IS_VENDOR_8723_A_CUT(rtlhal->version)) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], not 8723B cut, don't set Traditional TDMA!!\n");
+               return;
+       }
+
+       if (enable) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], turn TTDMA mode ON!!\n");
+               h2c_parameter[0] |= BIT(0);             /* function enable */
+               if (TDMA_1ANT == ant_num) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TTDMA_1ANT\n");
+                       h2c_parameter[0] |= BIT(1);
+               } else if (TDMA_2ANT == ant_num) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TTDMA_2ANT\n");
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], Unknown Ant\n");
+               }
+
+               if (TDMA_NAV_OFF == nav_en) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TTDMA_NAV_OFF\n");
+               } else if (TDMA_NAV_ON == nav_en) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex], TTDMA_NAV_ON\n");
+                       h2c_parameter[1] |= BIT(0);
+               }
+
+               rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], turn TTDMA mode OFF!!\n");
+       }
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], FW Traditional TDMA, write 0x33 = 0x%x\n",
+                h2c_parameter[0] << 8 | h2c_parameter[1]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0x33, 2, h2c_parameter);
+}
+
+static void rtl8723ae_dm_bt_set_fw_dac_swing_level(struct ieee80211_hw *hw,
+                                                  u8 dac_swing_lvl)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 h2c_parameter[1] = {0};
+
+       h2c_parameter[0] = dac_swing_lvl;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], Set Dac Swing Level = 0x%x\n", dac_swing_lvl);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], write 0x29 = 0x%x\n", h2c_parameter[0]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0x29, 1, h2c_parameter);
+}
+
+static void rtl8723ae_dm_bt_set_fw_bt_hid_info(struct ieee80211_hw *hw,
+                                              bool enable)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 h2c_parameter[1] = {0};
+
+       h2c_parameter[0] = 0;
+
+       if (enable) {
+               h2c_parameter[0] |= BIT(0);
+               rtlpcipriv->bt_coexist.fw_coexist_all_off = false;
+       }
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], Set BT HID information = 0x%x\n", enable);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], write 0x24 = 0x%x\n", h2c_parameter[0]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0x24, 1, h2c_parameter);
+}
+
+static void rtl8723ae_dm_bt_set_fw_bt_retry_index(struct ieee80211_hw *hw,
+                                                 u8 retry_index)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 h2c_parameter[1] = {0};
+
+       h2c_parameter[0] = retry_index;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], Set BT Retry Index=%d\n", retry_index);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], write 0x23 = 0x%x\n", h2c_parameter[0]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0x23, 1, h2c_parameter);
+}
+
+static void rtl8723ae_dm_bt_set_fw_wlan_act(struct ieee80211_hw *hw,
+                                           u8 wlan_act_hi, u8 wlan_act_lo)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 h2c_parameter_hi[1] = {0};
+       u8 h2c_parameter_lo[1] = {0};
+
+       h2c_parameter_hi[0] = wlan_act_hi;
+       h2c_parameter_lo[0] = wlan_act_lo;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], Set WLAN_ACT Hi:Lo = 0x%x/0x%x\n", wlan_act_hi,
+                wlan_act_lo);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], write 0x22 = 0x%x\n", h2c_parameter_hi[0]);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "[BTCoex], write 0x11 = 0x%x\n", h2c_parameter_lo[0]);
+
+       /* WLAN_ACT = High duration, unit:ms */
+       rtl8723ae_fill_h2c_cmd(hw, 0x22, 1, h2c_parameter_hi);
+       /*  WLAN_ACT = Low duration, unit:3*625us */
+       rtl8723ae_fill_h2c_cmd(hw, 0x11, 1, h2c_parameter_lo);
+}
+
+void rtl8723ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw, struct btdm_8723 *btdm)
+{
+       struct rtl_pci_priv     *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct btdm_8723 *btdm_8723 = &rtlhal->hal_coex_8723.btdm;
+       u8 i;
+       bool fw_current_inpsmode = false;
+       bool fw_ps_awake = true;
+
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FW_PSMODE_STATUS,
+                                     (u8 *)(&fw_current_inpsmode));
+       rtlpriv->cfg->ops->get_hw_reg(hw, HW_VAR_FWLPS_RF_ON,
+                                     (u8 *)(&fw_ps_awake));
+
+       /* check new setting is different than the old one,
+        * if all the same, don't do the setting again.
+        */
+       if (memcmp(btdm_8723, btdm, sizeof(struct btdm_8723)) == 0) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], the same coexist setting, return!!\n");
+               return;
+       } else {        /* save the new coexist setting */
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], UPDATE TO NEW COEX SETTING!!\n");
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new bAllOff = 0x%x/ 0x%x\n",
+                        btdm_8723->all_off, btdm->all_off);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new agc_table_en = 0x%x/ 0x%x\n",
+                        btdm_8723->agc_table_en, btdm->agc_table_en);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new adc_back_off_on = 0x%x/ 0x%x\n",
+                        btdm_8723->adc_back_off_on, btdm->adc_back_off_on);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new b2_ant_hid_en = 0x%x/ 0x%x\n",
+                        btdm_8723->b2_ant_hid_en, btdm->b2_ant_hid_en);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new bLowPenaltyRateAdaptive = 0x%x/ 0x%x\n",
+                        btdm_8723->low_penalty_rate_adaptive,
+                        btdm->low_penalty_rate_adaptive);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new bRfRxLpfShrink = 0x%x/ 0x%x\n",
+                        btdm_8723->rf_rx_lpf_shrink, btdm->rf_rx_lpf_shrink);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new bRejectAggrePkt = 0x%x/ 0x%x\n",
+                        btdm_8723->reject_aggre_pkt, btdm->reject_aggre_pkt);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new tdma_on = 0x%x/ 0x%x\n",
+                        btdm_8723->tdma_on, btdm->tdma_on);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new tdmaAnt = 0x%x/ 0x%x\n",
+                        btdm_8723->tdma_ant, btdm->tdma_ant);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new tdmaNav = 0x%x/ 0x%x\n",
+                        btdm_8723->tdma_nav, btdm->tdma_nav);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new tdma_dac_swing = 0x%x/ 0x%x\n",
+                        btdm_8723->tdma_dac_swing, btdm->tdma_dac_swing);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new fwDacSwingLvl = 0x%x/ 0x%x\n",
+                        btdm_8723->fw_dac_swing_lvl, btdm->fw_dac_swing_lvl);
+
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new bTraTdmaOn = 0x%x/ 0x%x\n",
+                        btdm_8723->tra_tdma_on, btdm->tra_tdma_on);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new traTdmaAnt = 0x%x/ 0x%x\n",
+                        btdm_8723->tra_tdma_ant, btdm->tra_tdma_ant);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new traTdmaNav = 0x%x/ 0x%x\n",
+                        btdm_8723->tra_tdma_nav, btdm->tra_tdma_nav);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new bPsTdmaOn = 0x%x/ 0x%x\n",
+                        btdm_8723->ps_tdma_on, btdm->ps_tdma_on);
+               for (i = 0; i < 5; i++) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "[BTCoex], original/new psTdmaByte[i] = 0x%x/ 0x%x\n",
+                                btdm_8723->ps_tdma_byte[i],
+                                btdm->ps_tdma_byte[i]);
+               }
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new bIgnoreWlanAct = 0x%x/ 0x%x\n",
+                        btdm_8723->ignore_wlan_act, btdm->ignore_wlan_act);
+
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new bPtaOn = 0x%x/ 0x%x\n",
+                        btdm_8723->pta_on, btdm->pta_on);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new val_0x6c0 = 0x%x/ 0x%x\n",
+                        btdm_8723->val_0x6c0, btdm->val_0x6c0);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new val_0x6c8 = 0x%x/ 0x%x\n",
+                        btdm_8723->val_0x6c8, btdm->val_0x6c8);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new val_0x6cc = 0x%x/ 0x%x\n",
+                        btdm_8723->val_0x6cc, btdm->val_0x6cc);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new sw_dac_swing_on = 0x%x/ 0x%x\n",
+                        btdm_8723->sw_dac_swing_on, btdm->sw_dac_swing_on);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new sw_dac_swing_lvl = 0x%x/ 0x%x\n",
+                        btdm_8723->sw_dac_swing_lvl,
+                        btdm->sw_dac_swing_lvl);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new wlanActHi = 0x%x/ 0x%x\n",
+                        btdm_8723->wlan_act_hi, btdm->wlan_act_hi);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new wlanActLo = 0x%x/ 0x%x\n",
+                        btdm_8723->wlan_act_lo, btdm->wlan_act_lo);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], original/new btRetryIndex = 0x%x/ 0x%x\n",
+                       btdm_8723->bt_retry_index, btdm->bt_retry_index);
+
+               memcpy(btdm_8723, btdm, sizeof(struct btdm_8723));
+       }
+       /*
+        * Here we only consider when Bt Operation
+        * inquiry/paging/pairing is ON
+        * we only need to turn off TDMA
+        */
+
+       if (rtlpcipriv->bt_coexist.hold_for_bt_operation) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], set to ignore wlanAct for BT OP!!\n");
+               rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, true);
+               return;
+       }
+
+       if (btdm->all_off) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], disable all coexist mechanism !!\n");
+               rtl8723ae_btdm_coex_all_off(hw);
+               return;
+       }
+
+       rtl8723ae_dm_bt_reject_ap_aggregated_packet(hw, btdm->reject_aggre_pkt);
+
+       if (btdm->low_penalty_rate_adaptive)
+               rtl8723ae_bt_set_penalty_tx_rate_adap(hw,
+                       BT_TX_RATE_ADAPTIVE_LOW_PENALTY);
+       else
+               rtl8723ae_bt_set_penalty_tx_rate_adap(hw,
+                       BT_TX_RATE_ADAPTIVE_NORMAL);
+
+       if (btdm->rf_rx_lpf_shrink)
+               rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(hw,
+                                        BT_RF_RX_LPF_CORNER_SHRINK);
+       else
+               rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(hw,
+                                        BT_RF_RX_LPF_CORNER_RESUME);
+
+       if (btdm->agc_table_en)
+               rtl8723ae_dm_bt_agc_table(hw, BT_AGCTABLE_ON);
+       else
+               rtl8723ae_dm_bt_agc_table(hw, BT_AGCTABLE_OFF);
+
+       if (btdm->adc_back_off_on)
+               rtl8723ae_dm_bt_bback_off_level(hw, BT_BB_BACKOFF_ON);
+       else
+               rtl8723ae_dm_bt_bback_off_level(hw, BT_BB_BACKOFF_OFF);
+
+       rtl8723ae_dm_bt_set_fw_bt_retry_index(hw, btdm->bt_retry_index);
+
+       rtl8723ae_dm_bt_set_fw_dac_swing_level(hw, btdm->fw_dac_swing_lvl);
+       rtl8723ae_dm_bt_set_fw_wlan_act(hw, btdm->wlan_act_hi,
+                                      btdm->wlan_act_lo);
+
+       rtl8723ae_dm_bt_set_coex_table(hw, btdm->val_0x6c0,
+               btdm->val_0x6c8, btdm->val_0x6cc);
+       rtl8723ae_dm_bt_set_hw_pta_mode(hw, btdm->pta_on);
+
+       /* Note: There is a constraint between TDMA and 2AntHID
+        * Only one of 2AntHid and tdma can be turned on
+        * We should turn off those mechanisms first
+        * and then turn on them on.
+       */
+       if (btdm->b2_ant_hid_en) {
+               /* turn off tdma */
+               rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
+                                                   btdm->tra_tdma_ant,
+                                                   btdm->tra_tdma_nav);
+               rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant,
+                                               btdm->tdma_nav,
+                                               btdm->tdma_dac_swing);
+
+               /* turn off Pstdma */
+               rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw,
+                                                     btdm->ignore_wlan_act);
+               /* Antenna control by PTA, 0x870 = 0x300. */
+               rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
+
+               /* turn on 2AntHid */
+               rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, true);
+               rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, true, true);
+       } else if (btdm->tdma_on) {
+               /* turn off 2AntHid */
+               rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false);
+               rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false);
+
+               /* turn off pstdma */
+               rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw,
+                                                     btdm->ignore_wlan_act);
+               /* Antenna control by PTA, 0x870 = 0x300. */
+               rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
+
+               /* turn on tdma */
+               rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
+                                btdm->tra_tdma_ant, btdm->tra_tdma_nav);
+               rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, true, btdm->tdma_ant,
+                                btdm->tdma_nav, btdm->tdma_dac_swing);
+       } else if (btdm->ps_tdma_on) {
+               /* turn off 2AntHid */
+               rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false);
+               rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false);
+
+               /* turn off tdma */
+               rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
+                                btdm->tra_tdma_ant, btdm->tra_tdma_nav);
+               rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant,
+                                btdm->tdma_nav, btdm->tdma_dac_swing);
+
+               /* turn on pstdma */
+               rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw,
+                                btdm->ignore_wlan_act);
+               rtl8723ae_dm_bt_set_fw_3a(hw,
+                       btdm->ps_tdma_byte[0],
+                       btdm->ps_tdma_byte[1],
+                       btdm->ps_tdma_byte[2],
+                       btdm->ps_tdma_byte[3],
+                       btdm->ps_tdma_byte[4]);
+       } else {
+               /* turn off 2AntHid */
+               rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false);
+               rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false);
+
+               /* turn off tdma */
+               rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, btdm->tra_tdma_on,
+                                btdm->tra_tdma_ant, btdm->tra_tdma_nav);
+               rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, btdm->tdma_ant,
+                                btdm->tdma_nav, btdm->tdma_dac_swing);
+
+               /* turn off pstdma */
+               rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw,
+                                                     btdm->ignore_wlan_act);
+               /* Antenna control by PTA, 0x870 = 0x300. */
+               rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
+       }
+
+       /* Note:
+        * We should add delay for making sure sw DacSwing can be set
+        *  sucessfully. Because of that rtl8723ae_dm_bt_set_fw_2_ant_hid()
+        * and rtl8723ae_dm_bt_set_fw_tdma_ctrl()
+        * will overwrite the reg 0x880.
+       */
+       mdelay(30);
+       rtl8723ae_dm_bt_set_sw_full_time_dac_swing(hw,
+               btdm->sw_dac_swing_on, btdm->sw_dac_swing_lvl);
+       rtl8723ae_dm_bt_set_fw_dec_bt_pwr(hw, btdm->dec_bt_pwr);
+}
+
+/*============================================================
+ * extern function start with BTDM_
+ *============================================================
+ */
+static u32 rtl8723ae_dm_bt_tx_rx_couter_h(struct ieee80211_hw *hw)
+{
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u32 counters = 0;
+
+       counters = rtlhal->hal_coex_8723.high_priority_tx +
+                  rtlhal->hal_coex_8723.high_priority_rx;
+       return counters;
+}
+
+static u32 rtl8723ae_dm_bt_tx_rx_couter_l(struct ieee80211_hw *hw)
+{
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       return rtlhal->hal_coex_8723.low_priority_tx +
+              rtlhal->hal_coex_8723.low_priority_rx;
+}
+
+static u8 rtl8723ae_dm_bt_bt_tx_rx_counter_level(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       u32 bt_tx_rx_cnt = 0;
+       u8 bt_tx_rx_cnt_lvl = 0;
+
+       bt_tx_rx_cnt = rtl8723ae_dm_bt_tx_rx_couter_h(hw) +
+                      rtl8723ae_dm_bt_tx_rx_couter_l(hw);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt);
+
+       rtlpcipriv->bt_coexist.cstate_h &=
+                ~(BT_COEX_STATE_BT_CNT_LEVEL_0 | BT_COEX_STATE_BT_CNT_LEVEL_1 |
+                 BT_COEX_STATE_BT_CNT_LEVEL_2);
+
+       if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_3) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], BT TxRx Counters at level 3\n");
+               bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_3;
+               rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_3;
+       } else if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_2) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], BT TxRx Counters at level 2\n");
+               bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_2;
+               rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_2;
+       } else if (bt_tx_rx_cnt >= BT_TXRX_CNT_THRES_1) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], BT TxRx Counters at level 1\n");
+               bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_1;
+               rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_1;
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], BT TxRx Counters at level 0\n");
+               bt_tx_rx_cnt_lvl = BT_TXRX_CNT_LEVEL_0;
+               rtlpcipriv->bt_coexist.cstate_h |= BT_COEX_STATE_BT_CNT_LEVEL_0;
+       }
+       return bt_tx_rx_cnt_lvl;
+}
+
+static void rtl8723ae_dm_bt_2_ant_hid_sco_esco(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct btdm_8723 btdm8723;
+       u8 bt_rssi_state, bt_rssi_state1;
+       u8 bt_tx_rx_cnt_lvl;
+
+       rtl8723ae_dm_bt_btdm_structure_reload(hw, &btdm8723);
+
+       btdm8723.rf_rx_lpf_shrink = true;
+       btdm8723.low_penalty_rate_adaptive = true;
+       btdm8723.reject_aggre_pkt = false;
+
+       bt_tx_rx_cnt_lvl = rtl8723ae_dm_bt_bt_tx_rx_counter_level(hw);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt_lvl);
+
+       if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, "HT40\n");
+               /* coex table */
+               btdm8723.val_0x6c0 = 0x55555555;
+               btdm8723.val_0x6c8 = 0xffff;
+               btdm8723.val_0x6cc = 0x3;
+
+               /* sw mechanism */
+               btdm8723.agc_table_en = false;
+               btdm8723.adc_back_off_on = false;
+               btdm8723.sw_dac_swing_on = false;
+
+               /* fw mechanism */
+               btdm8723.ps_tdma_on = true;
+               if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "[BTCoex], BT TxRx Counters >= 1400\n");
+                       btdm8723.ps_tdma_byte[0] = 0xa3;
+                       btdm8723.ps_tdma_byte[1] = 0x5;
+                       btdm8723.ps_tdma_byte[2] = 0x5;
+                       btdm8723.ps_tdma_byte[3] = 0x2;
+                       btdm8723.ps_tdma_byte[4] = 0x80;
+               } else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n");
+                       btdm8723.ps_tdma_byte[0] = 0xa3;
+                       btdm8723.ps_tdma_byte[1] = 0xa;
+                       btdm8723.ps_tdma_byte[2] = 0xa;
+                       btdm8723.ps_tdma_byte[3] = 0x2;
+                       btdm8723.ps_tdma_byte[4] = 0x80;
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "[BTCoex], BT TxRx Counters < 1200\n");
+                       btdm8723.ps_tdma_byte[0] = 0xa3;
+                       btdm8723.ps_tdma_byte[1] = 0xf;
+                       btdm8723.ps_tdma_byte[2] = 0xf;
+                       btdm8723.ps_tdma_byte[3] = 0x2;
+                       btdm8723.ps_tdma_byte[4] = 0x80;
+               }
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "HT20 or Legacy\n");
+               bt_rssi_state = rtl8723ae_dm_bt_check_coex_rssi_state(hw, 2,
+                                                                    47, 0);
+               bt_rssi_state1 = rtl8723ae_dm_bt_check_coex_rssi_state1(hw, 2,
+                                                                      27, 0);
+
+               /* coex table */
+               btdm8723.val_0x6c0 = 0x55555555;
+               btdm8723.val_0x6c8 = 0xffff;
+               btdm8723.val_0x6cc = 0x3;
+
+               /* sw mechanism */
+               if ((bt_rssi_state == BT_RSSI_STATE_HIGH) ||
+                   (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi high\n");
+                       btdm8723.agc_table_en = true;
+                       btdm8723.adc_back_off_on = true;
+                       btdm8723.sw_dac_swing_on = false;
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi low\n");
+                       btdm8723.agc_table_en = false;
+                       btdm8723.adc_back_off_on = false;
+                       btdm8723.sw_dac_swing_on = false;
+               }
+
+               /* fw mechanism */
+               btdm8723.ps_tdma_on = true;
+               if ((bt_rssi_state1 == BT_RSSI_STATE_HIGH) ||
+                   (bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi-1 high\n");
+                       /* only rssi high we need to do this,
+                        * when rssi low, the value will modified by fw
+                        */
+                       rtl_write_byte(rtlpriv, 0x883, 0x40);
+                       if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0x5;
+                               btdm8723.ps_tdma_byte[2] = 0x5;
+                               btdm8723.ps_tdma_byte[3] = 0x83;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xa;
+                               btdm8723.ps_tdma_byte[2] = 0xa;
+                               btdm8723.ps_tdma_byte[3] = 0x83;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters < 1200\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xf;
+                               btdm8723.ps_tdma_byte[2] = 0xf;
+                               btdm8723.ps_tdma_byte[3] = 0x83;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       }
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi-1 low\n");
+                       if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0x5;
+                               btdm8723.ps_tdma_byte[2] = 0x5;
+                               btdm8723.ps_tdma_byte[3] = 0x2;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xa;
+                               btdm8723.ps_tdma_byte[2] = 0xa;
+                               btdm8723.ps_tdma_byte[3] = 0x2;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters < 1200\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xf;
+                               btdm8723.ps_tdma_byte[2] = 0xf;
+                               btdm8723.ps_tdma_byte[3] = 0x2;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       }
+               }
+       }
+
+       if (rtl8723ae_dm_bt_need_to_dec_bt_pwr(hw))
+               btdm8723.dec_bt_pwr = true;
+
+       /* Always ignore WlanAct if bHid|bSCOBusy|bSCOeSCO */
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "[BTCoex], BT btInqPageStartTime = 0x%x, btTxRxCntLvl = %d\n",
+                rtlhal->hal_coex_8723.bt_inq_page_start_time,
+                bt_tx_rx_cnt_lvl);
+       if ((rtlhal->hal_coex_8723.bt_inq_page_start_time) ||
+           (BT_TXRX_CNT_LEVEL_3 == bt_tx_rx_cnt_lvl)) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], Set BT inquiry / page scan 0x3a setting\n");
+               btdm8723.ps_tdma_on = true;
+               btdm8723.ps_tdma_byte[0] = 0xa3;
+               btdm8723.ps_tdma_byte[1] = 0x5;
+               btdm8723.ps_tdma_byte[2] = 0x5;
+               btdm8723.ps_tdma_byte[3] = 0x2;
+               btdm8723.ps_tdma_byte[4] = 0x80;
+       }
+
+       if (rtl8723ae_dm_bt_is_coexist_state_changed(hw))
+               rtl8723ae_dm_bt_set_bt_dm(hw, &btdm8723);
+}
+
+static void rtl8723ae_dm_bt_2_ant_fta2dp(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct btdm_8723 btdm8723;
+       u8 bt_rssi_state, bt_rssi_state1;
+       u32 bt_tx_rx_cnt_lvl;
+
+       rtl8723ae_dm_bt_btdm_structure_reload(hw, &btdm8723);
+       btdm8723.rf_rx_lpf_shrink = true;
+       btdm8723.low_penalty_rate_adaptive = true;
+       btdm8723.reject_aggre_pkt = false;
+
+       bt_tx_rx_cnt_lvl = rtl8723ae_dm_bt_bt_tx_rx_counter_level(hw);
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "[BTCoex], BT TxRx Counters = %d\n", bt_tx_rx_cnt_lvl);
+
+       if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG, "HT40\n");
+               bt_rssi_state = rtl8723ae_dm_bt_check_coex_rssi_state(hw, 2,
+                                                                    37, 0);
+
+               /* coex table */
+               btdm8723.val_0x6c0 = 0x55555555;
+               btdm8723.val_0x6c8 = 0xffff;
+               btdm8723.val_0x6cc = 0x3;
+
+               /* sw mechanism */
+               btdm8723.agc_table_en = false;
+               btdm8723.adc_back_off_on = true;
+               btdm8723.sw_dac_swing_on = false;
+
+               /* fw mechanism */
+               btdm8723.ps_tdma_on = true;
+               if ((bt_rssi_state == BT_RSSI_STATE_HIGH) ||
+                   (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi high\n");
+                       if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0x5;
+                               btdm8723.ps_tdma_byte[2] = 0x5;
+                               btdm8723.ps_tdma_byte[3] = 0x81;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xa;
+                               btdm8723.ps_tdma_byte[2] = 0xa;
+                               btdm8723.ps_tdma_byte[3] = 0x81;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters < 1200\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xf;
+                               btdm8723.ps_tdma_byte[2] = 0xf;
+                               btdm8723.ps_tdma_byte[3] = 0x81;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       }
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi low\n");
+                       if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0x5;
+                               btdm8723.ps_tdma_byte[2] = 0x5;
+                               btdm8723.ps_tdma_byte[3] = 0x0;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xa;
+                               btdm8723.ps_tdma_byte[2] = 0xa;
+                               btdm8723.ps_tdma_byte[3] = 0x0;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters < 1200\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xf;
+                               btdm8723.ps_tdma_byte[2] = 0xf;
+                               btdm8723.ps_tdma_byte[3] = 0x0;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       }
+               }
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "HT20 or Legacy\n");
+               bt_rssi_state = rtl8723ae_dm_bt_check_coex_rssi_state(hw, 2,
+                                                                    47, 0);
+               bt_rssi_state1 = rtl8723ae_dm_bt_check_coex_rssi_state1(hw, 2,
+                                                                      27, 0);
+
+               /* coex table */
+               btdm8723.val_0x6c0 = 0x55555555;
+               btdm8723.val_0x6c8 = 0xffff;
+               btdm8723.val_0x6cc = 0x3;
+
+               /* sw mechanism */
+               if ((bt_rssi_state == BT_RSSI_STATE_HIGH) ||
+                   (bt_rssi_state == BT_RSSI_STATE_STAY_HIGH)) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi high\n");
+                       btdm8723.agc_table_en = true;
+                       btdm8723.adc_back_off_on = true;
+                       btdm8723.sw_dac_swing_on = false;
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi low\n");
+                       btdm8723.agc_table_en = false;
+                       btdm8723.adc_back_off_on = false;
+                       btdm8723.sw_dac_swing_on = false;
+               }
+
+               /* fw mechanism */
+               btdm8723.ps_tdma_on = true;
+               if ((bt_rssi_state1 == BT_RSSI_STATE_HIGH) ||
+                   (bt_rssi_state1 == BT_RSSI_STATE_STAY_HIGH)) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi-1 high\n");
+                       /* only rssi high we need to do this,
+                        * when rssi low, the value will modified by fw
+                        */
+                       rtl_write_byte(rtlpriv, 0x883, 0x40);
+                       if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0x5;
+                               btdm8723.ps_tdma_byte[2] = 0x5;
+                               btdm8723.ps_tdma_byte[3] = 0x81;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xa;
+                               btdm8723.ps_tdma_byte[2] = 0xa;
+                               btdm8723.ps_tdma_byte[3] = 0x81;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters < 1200\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xf;
+                               btdm8723.ps_tdma_byte[2] = 0xf;
+                               btdm8723.ps_tdma_byte[3] = 0x81;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       }
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "Wifi rssi-1 low\n");
+                       if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_2) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0x5;
+                               btdm8723.ps_tdma_byte[2] = 0x5;
+                               btdm8723.ps_tdma_byte[3] = 0x0;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else if (bt_tx_rx_cnt_lvl == BT_TXRX_CNT_LEVEL_1) {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters >= 1200 && < 1400\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xa;
+                               btdm8723.ps_tdma_byte[2] = 0xa;
+                               btdm8723.ps_tdma_byte[3] = 0x0;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                        "[BTCoex], BT TxRx Counters < 1200\n");
+                               btdm8723.ps_tdma_byte[0] = 0xa3;
+                               btdm8723.ps_tdma_byte[1] = 0xf;
+                               btdm8723.ps_tdma_byte[2] = 0xf;
+                               btdm8723.ps_tdma_byte[3] = 0x0;
+                               btdm8723.ps_tdma_byte[4] = 0x80;
+                       }
+               }
+       }
+
+       if (rtl8723ae_dm_bt_need_to_dec_bt_pwr(hw))
+               btdm8723.dec_bt_pwr = true;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "[BTCoex], BT btInqPageStartTime = 0x%x, btTxRxCntLvl = %d\n",
+                rtlhal->hal_coex_8723.bt_inq_page_start_time,
+                bt_tx_rx_cnt_lvl);
+
+       if ((rtlhal->hal_coex_8723.bt_inq_page_start_time) ||
+           (BT_TXRX_CNT_LEVEL_3 == bt_tx_rx_cnt_lvl)) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], Set BT inquiry / page scan 0x3a setting\n");
+               btdm8723.ps_tdma_on = true;
+               btdm8723.ps_tdma_byte[0] = 0xa3;
+               btdm8723.ps_tdma_byte[1] = 0x5;
+               btdm8723.ps_tdma_byte[2] = 0x5;
+               btdm8723.ps_tdma_byte[3] = 0x83;
+               btdm8723.ps_tdma_byte[4] = 0x80;
+       }
+
+       if (rtl8723ae_dm_bt_is_coexist_state_changed(hw))
+               rtl8723ae_dm_bt_set_bt_dm(hw, &btdm8723);
+}
+
+static void rtl8723ae_dm_bt_inq_page_monitor(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u32 cur_time = jiffies;
+
+       if (rtlhal->hal_coex_8723.c2h_bt_inquiry_page) {
+               /* bt inquiry or page is started. */
+               if (rtlhal->hal_coex_8723.bt_inq_page_start_time == 0) {
+                       rtlpcipriv->bt_coexist.cstate |=
+                                        BT_COEX_STATE_BT_INQ_PAGE;
+                       rtlhal->hal_coex_8723.bt_inq_page_start_time = cur_time;
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "[BTCoex], BT Inquiry/page is started at time : 0x%x\n",
+                                rtlhal->hal_coex_8723.bt_inq_page_start_time);
+               }
+       }
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "[BTCoex], BT Inquiry/page started time : 0x%x, cur_time : 0x%x\n",
+                rtlhal->hal_coex_8723.bt_inq_page_start_time, cur_time);
+
+       if (rtlhal->hal_coex_8723.bt_inq_page_start_time) {
+               if ((((long)cur_time -
+                   (long)rtlhal->hal_coex_8723.bt_inq_page_start_time) / HZ) >=
+                   10) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "[BTCoex], BT Inquiry/page >= 10sec!!!");
+                       rtlhal->hal_coex_8723.bt_inq_page_start_time = 0;
+                       rtlpcipriv->bt_coexist.cstate &=
+                                                ~BT_COEX_STATE_BT_INQ_PAGE;
+               }
+       }
+}
+
+static void rtl8723ae_dm_bt_reset_action_profile_state(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       rtlpcipriv->bt_coexist.cstate &=
+               ~(BT_COEX_STATE_PROFILE_HID | BT_COEX_STATE_PROFILE_A2DP |
+               BT_COEX_STATE_PROFILE_PAN | BT_COEX_STATE_PROFILE_SCO);
+
+       rtlpcipriv->bt_coexist.cstate &=
+               ~(BT_COEX_STATE_BTINFO_COMMON |
+               BT_COEX_STATE_BTINFO_B_HID_SCOESCO |
+               BT_COEX_STATE_BTINFO_B_FTP_A2DP);
+}
+
+static void _rtl8723ae_dm_bt_coexist_2_ant(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       u8 bt_retry_cnt;
+       u8 bt_info_original;
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "[BTCoex] Get bt info by fw!!\n");
+
+       _rtl8723_dm_bt_check_wifi_state(hw);
+
+       if (rtlhal->hal_coex_8723.c2h_bt_info_req_sent) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "[BTCoex] c2h for btInfo not rcvd yet!!\n");
+       }
+
+       bt_retry_cnt = rtlhal->hal_coex_8723.bt_retry_cnt;
+       bt_info_original = rtlhal->hal_coex_8723.c2h_bt_info_original;
+
+       /* when bt inquiry or page scan, we have to set h2c 0x25
+        * ignore wlanact for continuous 4x2secs
+        */
+       rtl8723ae_dm_bt_inq_page_monitor(hw);
+       rtl8723ae_dm_bt_reset_action_profile_state(hw);
+
+       if (rtl8723ae_dm_bt_is_2_ant_common_action(hw)) {
+               rtlpcipriv->bt_coexist.bt_profile_case = BT_COEX_MECH_COMMON;
+               rtlpcipriv->bt_coexist.bt_profile_action = BT_COEX_MECH_COMMON;
+
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "Action 2-Ant common.\n");
+       } else {
+               if ((bt_info_original & BTINFO_B_HID) ||
+                   (bt_info_original & BTINFO_B_SCO_BUSY) ||
+                   (bt_info_original & BTINFO_B_SCO_ESCO)) {
+                       rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_BTINFO_B_HID_SCOESCO;
+                       rtlpcipriv->bt_coexist.bt_profile_case =
+                                       BT_COEX_MECH_HID_SCO_ESCO;
+                       rtlpcipriv->bt_coexist.bt_profile_action =
+                                       BT_COEX_MECH_HID_SCO_ESCO;
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "[BTCoex], BTInfo: bHid|bSCOBusy|bSCOeSCO\n");
+                       rtl8723ae_dm_bt_2_ant_hid_sco_esco(hw);
+               } else if ((bt_info_original & BTINFO_B_FTP) ||
+                          (bt_info_original & BTINFO_B_A2DP)) {
+                       rtlpcipriv->bt_coexist.cstate |=
+                                       BT_COEX_STATE_BTINFO_B_FTP_A2DP;
+                       rtlpcipriv->bt_coexist.bt_profile_case =
+                                       BT_COEX_MECH_FTP_A2DP;
+                       rtlpcipriv->bt_coexist.bt_profile_action =
+                                       BT_COEX_MECH_FTP_A2DP;
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "BTInfo: bFTP|bA2DP\n");
+                       rtl8723ae_dm_bt_2_ant_fta2dp(hw);
+               } else {
+                       rtlpcipriv->bt_coexist.cstate |=
+                                        BT_COEX_STATE_BTINFO_B_HID_SCOESCO;
+                       rtlpcipriv->bt_coexist.bt_profile_case =
+                                        BT_COEX_MECH_NONE;
+                       rtlpcipriv->bt_coexist.bt_profile_action =
+                                        BT_COEX_MECH_NONE;
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                                "[BTCoex], BTInfo: undefined case!!!!\n");
+                       rtl8723ae_dm_bt_2_ant_hid_sco_esco(hw);
+               }
+       }
+}
+
+static void _rtl8723ae_dm_bt_coexist_1_ant(struct ieee80211_hw *hw)
+{
+}
+
+void rtl8723ae_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw)
+{
+       rtl8723ae_dm_bt_set_coex_table(hw, 0x5a5aaaaa, 0xcc, 0x3);
+       rtl8723ae_dm_bt_set_hw_pta_mode(hw, true);
+}
+
+void rtl8723ae_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw)
+{
+       rtl8723ae_dm_bt_set_fw_ignore_wlan_act(hw, false);
+       rtl8723ae_dm_bt_set_fw_3a(hw, 0x0, 0x0, 0x0, 0x8, 0x0);
+       rtl8723ae_dm_bt_set_fw_2_ant_hid(hw, false, false);
+       rtl8723ae_dm_bt_set_fw_tra_tdma_ctrl(hw, false,
+                                            TDMA_2ANT, TDMA_NAV_OFF);
+       rtl8723ae_dm_bt_set_fw_tdma_ctrl(hw, false, TDMA_2ANT,
+                               TDMA_NAV_OFF, TDMA_DAC_SWING_OFF);
+       rtl8723ae_dm_bt_set_fw_dac_swing_level(hw, 0);
+       rtl8723ae_dm_bt_set_fw_bt_hid_info(hw, false);
+       rtl8723ae_dm_bt_set_fw_bt_retry_index(hw, 2);
+       rtl8723ae_dm_bt_set_fw_wlan_act(hw, 0x10, 0x10);
+       rtl8723ae_dm_bt_set_fw_dec_bt_pwr(hw, false);
+}
+
+void rtl8723ae_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw)
+{
+       rtl8723ae_dm_bt_agc_table(hw, BT_AGCTABLE_OFF);
+       rtl8723ae_dm_bt_bback_off_level(hw, BT_BB_BACKOFF_OFF);
+       rtl8723ae_dm_bt_reject_ap_aggregated_packet(hw, false);
+
+       rtl8723ae_bt_set_penalty_tx_rate_adap(hw, BT_TX_RATE_ADAPTIVE_NORMAL);
+       rtl8723ae_dm_bt_set_sw_rf_rx_lpf_corner(hw, BT_RF_RX_LPF_CORNER_RESUME);
+       rtl8723ae_dm_bt_set_sw_full_time_dac_swing(hw, false, 0xc0);
+}
+
+static void rtl8723ae_dm_bt_query_bt_information(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       u8 h2c_parameter[1] = {0};
+
+       rtlhal->hal_coex_8723.c2h_bt_info_req_sent = true;
+
+       h2c_parameter[0] |=  BIT(0);
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "Query Bt information, write 0x38 = 0x%x\n",
+                h2c_parameter[0]);
+
+       rtl8723ae_fill_h2c_cmd(hw, 0x38, 1, h2c_parameter);
+}
+
+static void rtl8723ae_dm_bt_bt_hw_counters_monitor(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       u32 reg_htx_rx, reg_ltx_rx, u32_tmp;
+       u32 reg_htx, reg_hrx, reg_ltx, reg_lrx;
+
+       reg_htx_rx = REG_HIGH_PRIORITY_TXRX;
+       reg_ltx_rx = REG_LOW_PRIORITY_TXRX;
+
+       u32_tmp = rtl_read_dword(rtlpriv, reg_htx_rx);
+       reg_htx = u32_tmp & MASKLWORD;
+       reg_hrx = (u32_tmp & MASKHWORD)>>16;
+
+       u32_tmp = rtl_read_dword(rtlpriv, reg_ltx_rx);
+       reg_ltx = u32_tmp & MASKLWORD;
+       reg_lrx = (u32_tmp & MASKHWORD)>>16;
+
+       if (rtlpcipriv->bt_coexist.lps_counter > 1) {
+               reg_htx %= rtlpcipriv->bt_coexist.lps_counter;
+               reg_hrx %= rtlpcipriv->bt_coexist.lps_counter;
+               reg_ltx %= rtlpcipriv->bt_coexist.lps_counter;
+               reg_lrx %= rtlpcipriv->bt_coexist.lps_counter;
+       }
+
+       rtlhal->hal_coex_8723.high_priority_tx = reg_htx;
+       rtlhal->hal_coex_8723.high_priority_rx = reg_hrx;
+       rtlhal->hal_coex_8723.low_priority_tx = reg_ltx;
+       rtlhal->hal_coex_8723.low_priority_rx = reg_lrx;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "High Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n",
+                reg_htx_rx, reg_htx, reg_htx, reg_hrx, reg_hrx);
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "Low Priority Tx/Rx (reg 0x%x)=%x(%d)/%x(%d)\n",
+                reg_ltx_rx, reg_ltx, reg_ltx, reg_lrx, reg_lrx);
+       rtlpcipriv->bt_coexist.lps_counter = 0;
+}
+
+static void rtl8723ae_dm_bt_bt_enable_disable_check(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       bool bt_alife = true;
+
+       if (rtlhal->hal_coex_8723.high_priority_tx == 0 &&
+           rtlhal->hal_coex_8723.high_priority_rx == 0 &&
+           rtlhal->hal_coex_8723.low_priority_tx == 0 &&
+           rtlhal->hal_coex_8723.low_priority_rx == 0)
+               bt_alife = false;
+       if (rtlhal->hal_coex_8723.high_priority_tx == 0xeaea &&
+           rtlhal->hal_coex_8723.high_priority_rx == 0xeaea &&
+           rtlhal->hal_coex_8723.low_priority_tx == 0xeaea &&
+           rtlhal->hal_coex_8723.low_priority_rx == 0xeaea)
+               bt_alife = false;
+       if (rtlhal->hal_coex_8723.high_priority_tx == 0xffff &&
+           rtlhal->hal_coex_8723.high_priority_rx == 0xffff &&
+           rtlhal->hal_coex_8723.low_priority_tx == 0xffff &&
+           rtlhal->hal_coex_8723.low_priority_rx == 0xffff)
+               bt_alife = false;
+       if (bt_alife) {
+               rtlpcipriv->bt_coexist.bt_active_zero_cnt = 0;
+               rtlpcipriv->bt_coexist.cur_bt_disabled = false;
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "8723A BT is enabled !!\n");
+       } else {
+               rtlpcipriv->bt_coexist.bt_active_zero_cnt++;
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "8723A bt all counters = 0, %d times!!\n",
+                        rtlpcipriv->bt_coexist.bt_active_zero_cnt);
+               if (rtlpcipriv->bt_coexist.bt_active_zero_cnt >= 2) {
+                       rtlpcipriv->bt_coexist.cur_bt_disabled = true;
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "8723A BT is disabled !!\n");
+               }
+       }
+       if (rtlpcipriv->bt_coexist.pre_bt_disabled !=
+               rtlpcipriv->bt_coexist.cur_bt_disabled) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "8723A BT is from %s to %s!!\n",
+                        (rtlpcipriv->bt_coexist.pre_bt_disabled ?
+                        "disabled" : "enabled"),
+                        (rtlpcipriv->bt_coexist.cur_bt_disabled ?
+                        "disabled" : "enabled"));
+               rtlpcipriv->bt_coexist.pre_bt_disabled
+                       = rtlpcipriv->bt_coexist.cur_bt_disabled;
+       }
+}
+
+
+void rtl8723ae_dm_bt_coexist_8723(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+
+       rtl8723ae_dm_bt_query_bt_information(hw);
+       rtl8723ae_dm_bt_bt_hw_counters_monitor(hw);
+       rtl8723ae_dm_bt_bt_enable_disable_check(hw);
+
+       if (rtlpcipriv->bt_coexist.bt_ant_num == ANT_X2) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], 2 Ant mechanism\n");
+               _rtl8723ae_dm_bt_coexist_2_ant(hw);
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "[BTCoex], 1 Ant mechanism\n");
+               _rtl8723ae_dm_bt_coexist_1_ant(hw);
+       }
+
+       if (!rtl8723ae_dm_bt_is_same_coexist_state(hw)) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTCoex], Coexist State[bitMap] change from 0x%x%8x to 0x%x%8x\n",
+                        rtlpcipriv->bt_coexist.previous_state_h,
+                        rtlpcipriv->bt_coexist.previous_state,
+                        rtlpcipriv->bt_coexist.cstate_h,
+                        rtlpcipriv->bt_coexist.cstate);
+               rtlpcipriv->bt_coexist.previous_state
+                       = rtlpcipriv->bt_coexist.cstate;
+               rtlpcipriv->bt_coexist.previous_state_h
+                       = rtlpcipriv->bt_coexist.cstate_h;
+       }
+}
+
+static void rtl8723ae_dm_bt_parse_bt_info(struct ieee80211_hw *hw,
+                                         u8 *tmbuf, u8 len)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtlpriv);
+       struct rtl_pci_priv *rtlpcipriv = rtl_pcipriv(hw);
+       u8 bt_info;
+       u8 i;
+
+       rtlhal->hal_coex_8723.c2h_bt_info_req_sent = false;
+       rtlhal->hal_coex_8723.bt_retry_cnt = 0;
+       for (i = 0; i < len; i++) {
+               if (i == 0)
+                       rtlhal->hal_coex_8723.c2h_bt_info_original = tmbuf[i];
+               else if (i == 1)
+                       rtlhal->hal_coex_8723.bt_retry_cnt = tmbuf[i];
+               if (i == len-1) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "0x%2x]", tmbuf[i]);
+               } else {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "0x%2x, ", tmbuf[i]);
+               }
+       }
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                "BT info bt_info (Data)= 0x%x\n",
+                rtlhal->hal_coex_8723.c2h_bt_info_original);
+       bt_info = rtlhal->hal_coex_8723.c2h_bt_info_original;
+
+       if (bt_info & BIT(2))
+               rtlhal->hal_coex_8723.c2h_bt_inquiry_page = true;
+       else
+               rtlhal->hal_coex_8723.c2h_bt_inquiry_page = false;
+
+       if (bt_info & BTINFO_B_CONNECTION) {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTC2H], BTInfo: bConnect=true\n");
+               rtlpcipriv->bt_coexist.bt_busy = true;
+               rtlpcipriv->bt_coexist.cstate &= ~BT_COEX_STATE_BT_IDLE;
+       } else {
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_DMESG,
+                        "[BTC2H], BTInfo: bConnect=false\n");
+               rtlpcipriv->bt_coexist.bt_busy = false;
+               rtlpcipriv->bt_coexist.cstate |= BT_COEX_STATE_BT_IDLE;
+       }
+}
+void rtl_8723e_c2h_command_handle(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct c2h_evt_hdr c2h_event;
+       u8 *ptmbuf;
+       u8 index;
+       u8 u1tmp;
+
+       memset(&c2h_event, 0, sizeof(c2h_event));
+       u1tmp = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL);
+       RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+                "&&&&&&: REG_C2HEVT_MSG_NORMAL is 0x%x\n", u1tmp);
+       c2h_event.cmd_id = u1tmp & 0xF;
+       c2h_event.cmd_len = (u1tmp & 0xF0) >> 4;
+       c2h_event.cmd_seq = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL + 1);
+       RT_TRACE(rtlpriv, COMP_FW, DBG_DMESG,
+                "cmd_id: %d, cmd_len: %d, cmd_seq: %d\n",
+                c2h_event.cmd_id , c2h_event.cmd_len, c2h_event.cmd_seq);
+       u1tmp = rtl_read_byte(rtlpriv, 0x01AF);
+       if (u1tmp == C2H_EVT_HOST_CLOSE) {
+               return;
+       } else if (u1tmp != C2H_EVT_FW_CLOSE) {
+               rtl_write_byte(rtlpriv, 0x1AF, 0x00);
+               return;
+       }
+       ptmbuf = kmalloc(c2h_event.cmd_len, GFP_KERNEL);
+       if (ptmbuf == NULL) {
+               RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+                        "malloc cmd buf failed\n");
+               return;
+       }
+
+       /* Read the content */
+       for (index = 0; index < c2h_event.cmd_len; index++)
+               ptmbuf[index] = rtl_read_byte(rtlpriv, REG_C2HEVT_MSG_NORMAL +
+                                 2 + index);
+
+       switch (c2h_event.cmd_id) {
+       case C2H_BT_RSSI:
+               break;
+
+       case C2H_BT_OP_MODE:
+                       break;
+
+       case BT_INFO:
+               RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+                        "BT info Byte[0] (ID) is 0x%x\n", c2h_event.cmd_id);
+               RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+                        "BT info Byte[1] (Seq) is 0x%x\n", c2h_event.cmd_seq);
+               RT_TRACE(rtlpriv, COMP_FW, DBG_TRACE,
+                        "BT info Byte[2] (Data)= 0x%x\n", ptmbuf[0]);
+
+               rtl8723ae_dm_bt_parse_bt_info(hw, ptmbuf, c2h_event.cmd_len);
+               break;
+       default:
+               break;
+       }
+       kfree(ptmbuf);
+
+       rtl_write_byte(rtlpriv, 0x01AF, C2H_EVT_HOST_CLOSE);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h b/drivers/net/wireless/rtlwifi/rtl8723ae/hal_btc.h
new file mode 100644 (file)
index 0000000..4325ecd
--- /dev/null
@@ -0,0 +1,151 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ ****************************************************************************
+ */
+
+#ifndef __RTL8723E_HAL_BTC_H__
+#define __RTL8723E_HAL_BTC_H__
+
+#include "../wifi.h"
+#include "btc.h"
+#include "hal_bt_coexist.h"
+
+#define        BT_TXRX_CNT_THRES_1             1200
+#define        BT_TXRX_CNT_THRES_2             1400
+#define        BT_TXRX_CNT_THRES_3             3000
+#define        BT_TXRX_CNT_LEVEL_0             0       /* < 1200 */
+#define        BT_TXRX_CNT_LEVEL_1             1       /* >= 1200 && < 1400 */
+#define        BT_TXRX_CNT_LEVEL_2             2       /* >= 1400 */
+#define        BT_TXRX_CNT_LEVEL_3             3
+
+/* TDMA mode definition */
+#define        TDMA_2ANT               0
+#define        TDMA_1ANT               1
+#define        TDMA_NAV_OFF            0
+#define        TDMA_NAV_ON             1
+#define        TDMA_DAC_SWING_OFF      0
+#define        TDMA_DAC_SWING_ON       1
+
+/* PTA mode related definition */
+#define        BT_PTA_MODE_OFF         0
+#define        BT_PTA_MODE_ON          1
+
+/* Penalty Tx Rate Adaptive */
+#define        BT_TX_RATE_ADAPTIVE_NORMAL      0
+#define        BT_TX_RATE_ADAPTIVE_LOW_PENALTY 1
+
+/* RF Corner */
+#define        BT_RF_RX_LPF_CORNER_RESUME      0
+#define        BT_RF_RX_LPF_CORNER_SHRINK      1
+
+#define C2H_EVT_HOST_CLOSE             0x00
+#define C2H_EVT_FW_CLOSE               0xFF
+
+enum bt_traffic_mode {
+       BT_MOTOR_EXT_BE = 0x00,
+       BT_MOTOR_EXT_GUL = 0x01,
+       BT_MOTOR_EXT_GUB = 0x02,
+       BT_MOTOR_EXT_GULB = 0x03
+};
+
+enum bt_traffic_mode_profile {
+       BT_PROFILE_NONE,
+       BT_PROFILE_A2DP,
+       BT_PROFILE_PAN,
+       BT_PROFILE_HID,
+       BT_PROFILE_SCO
+};
+
+enum hci_ext_bt_operation {
+       HCI_BT_OP_NONE = 0x0,
+       HCI_BT_OP_INQUIRE_START = 0x1,
+       HCI_BT_OP_INQUIRE_FINISH = 0x2,
+       HCI_BT_OP_PAGING_START = 0x3,
+       HCI_BT_OP_PAGING_SUCCESS = 0x4,
+       HCI_BT_OP_PAGING_UNSUCCESS = 0x5,
+       HCI_BT_OP_PAIRING_START = 0x6,
+       HCI_BT_OP_PAIRING_FINISH = 0x7,
+       HCI_BT_OP_BT_DEV_ENABLE = 0x8,
+       HCI_BT_OP_BT_DEV_DISABLE = 0x9,
+       HCI_BT_OP_MAX,
+};
+
+enum bt_spec {
+       BT_SPEC_1_0_b = 0x00,
+       BT_SPEC_1_1 = 0x01,
+       BT_SPEC_1_2 = 0x02,
+       BT_SPEC_2_0_EDR = 0x03,
+       BT_SPEC_2_1_EDR = 0x04,
+       BT_SPEC_3_0_HS = 0x05,
+       BT_SPEC_4_0 = 0x06
+};
+
+struct c2h_evt_hdr {
+       u8 cmd_id;
+       u8 cmd_len;
+       u8 cmd_seq;
+};
+
+enum bt_state {
+       BT_INFO_STATE_DISABLED = 0,
+       BT_INFO_STATE_NO_CONNECTION = 1,
+       BT_INFO_STATE_CONNECT_IDLE = 2,
+       BT_INFO_STATE_INQ_OR_PAG = 3,
+       BT_INFO_STATE_ACL_ONLY_BUSY = 4,
+       BT_INFO_STATE_SCO_ONLY_BUSY = 5,
+       BT_INFO_STATE_ACL_SCO_BUSY = 6,
+       BT_INFO_STATE_HID_BUSY = 7,
+       BT_INFO_STATE_HID_SCO_BUSY = 8,
+       BT_INFO_STATE_MAX = 7
+};
+
+enum rtl8723ae_c2h_evt {
+       C2H_DBG = 0,
+       C2H_TSF = 1,
+       C2H_AP_RPT_RSP = 2,
+       C2H_CCX_TX_RPT = 3,     /* The FW notify the report of the specific */
+                               /* tx packet. */
+       C2H_BT_RSSI = 4,
+       C2H_BT_OP_MODE = 5,
+       C2H_HW_INFO_EXCH = 10,
+       C2H_C2H_H2C_TEST = 11,
+       BT_INFO = 12,
+       MAX_C2HEVENT
+};
+
+void rtl8723ae_dm_bt_fw_coex_all_off_8723a(struct ieee80211_hw *hw);
+void rtl8723ae_dm_bt_sw_coex_all_off_8723a(struct ieee80211_hw *hw);
+void rtl8723ae_dm_bt_hw_coex_all_off_8723a(struct ieee80211_hw *hw);
+void rtl8723ae_dm_bt_coexist_8723(struct ieee80211_hw *hw);
+void rtl8723ae_dm_bt_set_bt_dm(struct ieee80211_hw *hw,
+                             struct btdm_8723 *p_btdm);
+void rtl_8723e_c2h_command_handle(struct ieee80211_hw *hw);
+void rtl_8723e_bt_wifi_media_status_notify(struct ieee80211_hw *hw,
+                                          bool mstatus);
+void rtl8723ae_bt_coex_off_before_lps(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.c
new file mode 100644 (file)
index 0000000..0a8c038
--- /dev/null
@@ -0,0 +1,2380 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../efuse.h"
+#include "../base.h"
+#include "../regd.h"
+#include "../cam.h"
+#include "../ps.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "fw.h"
+#include "led.h"
+#include "hw.h"
+#include "pwrseqcmd.h"
+#include "pwrseq.h"
+#include "btc.h"
+
+static void _rtl8723ae_set_bcn_ctrl_reg(struct ieee80211_hw *hw,
+                                       u8 set_bits, u8 clear_bits)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpci->reg_bcn_ctrl_val |= set_bits;
+       rtlpci->reg_bcn_ctrl_val &= ~clear_bits;
+
+       rtl_write_byte(rtlpriv, REG_BCN_CTRL, (u8) rtlpci->reg_bcn_ctrl_val);
+}
+
+static void _rtl8723ae_stop_tx_beacon(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmp1byte;
+
+       tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+       rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte & (~BIT(6)));
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0x64);
+       tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+       tmp1byte &= ~(BIT(0));
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl8723ae_resume_tx_beacon(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmp1byte;
+
+       tmp1byte = rtl_read_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2);
+       rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2, tmp1byte | BIT(6));
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+       tmp1byte = rtl_read_byte(rtlpriv, REG_TBTT_PROHIBIT + 2);
+       tmp1byte |= BIT(1);
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 2, tmp1byte);
+}
+
+static void _rtl8723ae_enable_bcn_sufunc(struct ieee80211_hw *hw)
+{
+       _rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(1));
+}
+
+static void _rtl8723ae_disable_bcn_sufunc(struct ieee80211_hw *hw)
+{
+       _rtl8723ae_set_bcn_ctrl_reg(hw, BIT(1), 0);
+}
+
+void rtl8723ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       switch (variable) {
+       case HW_VAR_RCR:
+               *((u32 *) (val)) = rtlpci->receive_config;
+               break;
+       case HW_VAR_RF_STATE:
+               *((enum rf_pwrstate *)(val)) = ppsc->rfpwr_state;
+               break;
+       case HW_VAR_FWLPS_RF_ON:{
+               enum rf_pwrstate rfState;
+               u32 val_rcr;
+
+               rtlpriv->cfg->ops->get_hw_reg(hw,
+                                             HW_VAR_RF_STATE,
+                                             (u8 *) (&rfState));
+               if (rfState == ERFOFF) {
+                       *((bool *) (val)) = true;
+               } else {
+                       val_rcr = rtl_read_dword(rtlpriv, REG_RCR);
+                       val_rcr &= 0x00070000;
+                       if (val_rcr)
+                               *((bool *) (val)) = false;
+                       else
+                               *((bool *) (val)) = true;
+               }
+               break; }
+       case HW_VAR_FW_PSMODE_STATUS:
+               *((bool *) (val)) = ppsc->fw_current_inpsmode;
+               break;
+       case HW_VAR_CORRECT_TSF:{
+               u64 tsf;
+               u32 *ptsf_low = (u32 *)&tsf;
+               u32 *ptsf_high = ((u32 *)&tsf) + 1;
+
+               *ptsf_high = rtl_read_dword(rtlpriv, (REG_TSFTR + 4));
+               *ptsf_low = rtl_read_dword(rtlpriv, REG_TSFTR);
+
+               *((u64 *) (val)) = tsf;
+
+               break; }
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       }
+}
+
+void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       u8 idx;
+
+       switch (variable) {
+       case HW_VAR_ETHER_ADDR:
+               for (idx = 0; idx < ETH_ALEN; idx++) {
+                       rtl_write_byte(rtlpriv, (REG_MACID + idx),
+                                      val[idx]);
+               }
+               break;
+       case HW_VAR_BASIC_RATE:{
+               u16 rate_cfg = ((u16 *) val)[0];
+               u8 rate_index = 0;
+               rate_cfg = rate_cfg & 0x15f;
+               rate_cfg |= 0x01;
+               rtl_write_byte(rtlpriv, REG_RRSR, rate_cfg & 0xff);
+               rtl_write_byte(rtlpriv, REG_RRSR + 1,
+                              (rate_cfg >> 8) & 0xff);
+               while (rate_cfg > 0x1) {
+                       rate_cfg = (rate_cfg >> 1);
+                       rate_index++;
+               }
+               rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL,
+                              rate_index);
+               break; }
+       case HW_VAR_BSSID:
+               for (idx = 0; idx < ETH_ALEN; idx++) {
+                       rtl_write_byte(rtlpriv, (REG_BSSID + idx),
+                                      val[idx]);
+               }
+               break;
+       case HW_VAR_SIFS:
+               rtl_write_byte(rtlpriv, REG_SIFS_CTX + 1, val[0]);
+               rtl_write_byte(rtlpriv, REG_SIFS_TRX + 1, val[1]);
+
+               rtl_write_byte(rtlpriv, REG_SPEC_SIFS + 1, val[0]);
+               rtl_write_byte(rtlpriv, REG_MAC_SPEC_SIFS + 1, val[0]);
+
+               if (!mac->ht_enable)
+                       rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+                                      0x0e0e);
+               else
+                       rtl_write_word(rtlpriv, REG_RESP_SIFS_OFDM,
+                                      *((u16 *) val));
+               break;
+       case HW_VAR_SLOT_TIME:{
+               u8 e_aci;
+
+               RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+                        "HW_VAR_SLOT_TIME %x\n", val[0]);
+
+               rtl_write_byte(rtlpriv, REG_SLOT, val[0]);
+
+               for (e_aci = 0; e_aci < AC_MAX; e_aci++) {
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                     HW_VAR_AC_PARAM,
+                                                     (u8 *) (&e_aci));
+               }
+               break; }
+       case HW_VAR_ACK_PREAMBLE:{
+               u8 reg_tmp;
+               u8 short_preamble = (bool) (*(u8 *) val);
+               reg_tmp = (mac->cur_40_prime_sc) << 5;
+               if (short_preamble)
+                       reg_tmp |= 0x80;
+
+               rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_tmp);
+               break; }
+       case HW_VAR_AMPDU_MIN_SPACE:{
+               u8 min_spacing_to_set;
+               u8 sec_min_space;
+
+               min_spacing_to_set = *((u8 *) val);
+               if (min_spacing_to_set <= 7) {
+                       sec_min_space = 0;
+
+                       if (min_spacing_to_set < sec_min_space)
+                               min_spacing_to_set = sec_min_space;
+
+                       mac->min_space_cfg = ((mac->min_space_cfg &
+                                              0xf8) |
+                                             min_spacing_to_set);
+
+                       *val = min_spacing_to_set;
+
+                       RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+                                "Set HW_VAR_AMPDU_MIN_SPACE: %#x\n",
+                                 mac->min_space_cfg);
+
+                       rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+                                      mac->min_space_cfg);
+               }
+               break; }
+       case HW_VAR_SHORTGI_DENSITY:{
+               u8 density_to_set;
+
+               density_to_set = *((u8 *) val);
+               mac->min_space_cfg |= (density_to_set << 3);
+
+               RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+                        "Set HW_VAR_SHORTGI_DENSITY: %#x\n",
+                        mac->min_space_cfg);
+
+               rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE,
+                              mac->min_space_cfg);
+
+               break; }
+       case HW_VAR_AMPDU_FACTOR:{
+               u8 regtoset_normal[4] = {0x41, 0xa8, 0x72, 0xb9};
+               u8 regtoset_bt[4] = {0x31, 0x74, 0x42, 0x97};
+               u8 factor_toset;
+               u8 *p_regtoset = NULL;
+               u8 index;
+
+               if ((pcipriv->bt_coexist.bt_coexistence) &&
+                   (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
+                       p_regtoset = regtoset_bt;
+               else
+                       p_regtoset = regtoset_normal;
+
+               factor_toset = *((u8 *) val);
+               if (factor_toset <= 3) {
+                       factor_toset = (1 << (factor_toset + 2));
+                       if (factor_toset > 0xf)
+                               factor_toset = 0xf;
+
+                       for (index = 0; index < 4; index++) {
+                               if ((p_regtoset[index] & 0xf0) >
+                                   (factor_toset << 4))
+                                       p_regtoset[index] =
+                                           (p_regtoset[index] & 0x0f) |
+                                           (factor_toset << 4);
+
+                               if ((p_regtoset[index] & 0x0f) >
+                                   factor_toset)
+                                       p_regtoset[index] =
+                                           (p_regtoset[index] & 0xf0) |
+                                           (factor_toset);
+
+                               rtl_write_byte(rtlpriv,
+                                              (REG_AGGLEN_LMT + index),
+                                              p_regtoset[index]);
+
+                       }
+
+                       RT_TRACE(rtlpriv, COMP_MLME, DBG_LOUD,
+                                "Set HW_VAR_AMPDU_FACTOR: %#x\n",
+                                factor_toset);
+               }
+               break; }
+       case HW_VAR_AC_PARAM:{
+               u8 e_aci = *((u8 *) val);
+               rtl8723ae_dm_init_edca_turbo(hw);
+
+               if (rtlpci->acm_method != eAcmWay2_SW)
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                     HW_VAR_ACM_CTRL,
+                                                     (u8 *) (&e_aci));
+               break; }
+       case HW_VAR_ACM_CTRL:{
+               u8 e_aci = *((u8 *) val);
+               union aci_aifsn *p_aci_aifsn =
+                   (union aci_aifsn *)(&(mac->ac[0].aifs));
+               u8 acm = p_aci_aifsn->f.acm;
+               u8 acm_ctrl = rtl_read_byte(rtlpriv, REG_ACMHWCTRL);
+
+               acm_ctrl |= ((rtlpci->acm_method == 2) ? 0x0 : 0x1);
+
+               if (acm) {
+                       switch (e_aci) {
+                       case AC0_BE:
+                               acm_ctrl |= AcmHw_BeqEn;
+                               break;
+                       case AC2_VI:
+                               acm_ctrl |= AcmHw_ViqEn;
+                               break;
+                       case AC3_VO:
+                               acm_ctrl |= AcmHw_VoqEn;
+                               break;
+                       default:
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                        "HW_VAR_ACM_CTRL acm set failed: eACI is %d\n",
+                                        acm);
+                               break;
+                       }
+               } else {
+                       switch (e_aci) {
+                       case AC0_BE:
+                               acm_ctrl &= (~AcmHw_BeqEn);
+                               break;
+                       case AC2_VI:
+                               acm_ctrl &= (~AcmHw_ViqEn);
+                               break;
+                       case AC3_VO:
+                               acm_ctrl &= (~AcmHw_BeqEn);
+                               break;
+                       default:
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                        "switch case not processed\n");
+                               break;
+                       }
+               }
+
+               RT_TRACE(rtlpriv, COMP_QOS, DBG_TRACE,
+                        "SetHwReg8190pci(): [HW_VAR_ACM_CTRL] Write 0x%X\n",
+                        acm_ctrl);
+               rtl_write_byte(rtlpriv, REG_ACMHWCTRL, acm_ctrl);
+               break; }
+       case HW_VAR_RCR:
+               rtl_write_dword(rtlpriv, REG_RCR, ((u32 *) (val))[0]);
+               rtlpci->receive_config = ((u32 *) (val))[0];
+               break;
+       case HW_VAR_RETRY_LIMIT:{
+               u8 retry_limit = ((u8 *) (val))[0];
+
+               rtl_write_word(rtlpriv, REG_RL,
+                              retry_limit << RETRY_LIMIT_SHORT_SHIFT |
+                              retry_limit << RETRY_LIMIT_LONG_SHIFT);
+               break; }
+       case HW_VAR_DUAL_TSF_RST:
+               rtl_write_byte(rtlpriv, REG_DUAL_TSF_RST, (BIT(0) | BIT(1)));
+               break;
+       case HW_VAR_EFUSE_BYTES:
+               rtlefuse->efuse_usedbytes = *((u16 *) val);
+               break;
+       case HW_VAR_EFUSE_USAGE:
+               rtlefuse->efuse_usedpercentage = *((u8 *) val);
+               break;
+       case HW_VAR_IO_CMD:
+               rtl8723ae_phy_set_io_cmd(hw, (*(enum io_type *)val));
+               break;
+       case HW_VAR_WPA_CONFIG:
+               rtl_write_byte(rtlpriv, REG_SECCFG, *((u8 *) val));
+               break;
+       case HW_VAR_SET_RPWM:{
+               u8 rpwm_val;
+
+               rpwm_val = rtl_read_byte(rtlpriv, REG_PCIE_HRPWM);
+               udelay(1);
+
+               if (rpwm_val & BIT(7)) {
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+                                      (*(u8 *) val));
+               } else {
+                       rtl_write_byte(rtlpriv, REG_PCIE_HRPWM,
+                                      ((*(u8 *) val) | BIT(7)));
+               }
+
+               break; }
+       case HW_VAR_H2C_FW_PWRMODE:{
+               u8 psmode = (*(u8 *) val);
+
+               if (psmode != FW_PS_ACTIVE_MODE)
+                       rtl8723ae_dm_rf_saving(hw, true);
+
+               rtl8723ae_set_fw_pwrmode_cmd(hw, (*(u8 *) val));
+               break; }
+       case HW_VAR_FW_PSMODE_STATUS:
+               ppsc->fw_current_inpsmode = *((bool *) val);
+               break;
+       case HW_VAR_H2C_FW_JOINBSSRPT:{
+               u8 mstatus = (*(u8 *) val);
+               u8 tmp_regcr, tmp_reg422;
+               bool recover = false;
+
+               if (mstatus == RT_MEDIA_CONNECT) {
+                       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_AID, NULL);
+
+                       tmp_regcr = rtl_read_byte(rtlpriv, REG_CR + 1);
+                       rtl_write_byte(rtlpriv, REG_CR + 1,
+                                      (tmp_regcr | BIT(0)));
+
+                       _rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(3));
+                       _rtl8723ae_set_bcn_ctrl_reg(hw, BIT(4), 0);
+
+                       tmp_reg422 = rtl_read_byte(rtlpriv,
+                                    REG_FWHW_TXQ_CTRL + 2);
+                       if (tmp_reg422 & BIT(6))
+                               recover = true;
+                       rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+                                      tmp_reg422 & (~BIT(6)));
+
+                       rtl8723ae_set_fw_rsvdpagepkt(hw, 0);
+
+                       _rtl8723ae_set_bcn_ctrl_reg(hw, BIT(3), 0);
+                       _rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(4));
+
+                       if (recover)
+                               rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 2,
+                                              tmp_reg422);
+
+                       rtl_write_byte(rtlpriv, REG_CR + 1,
+                                      (tmp_regcr & ~(BIT(0))));
+               }
+               rtl8723ae_set_fw_joinbss_report_cmd(hw, (*(u8 *) val));
+
+               break; }
+       case HW_VAR_AID:{
+               u16 u2btmp;
+               u2btmp = rtl_read_word(rtlpriv, REG_BCN_PSR_RPT);
+               u2btmp &= 0xC000;
+               rtl_write_word(rtlpriv, REG_BCN_PSR_RPT, (u2btmp |
+                               mac->assoc_id));
+               break; }
+       case HW_VAR_CORRECT_TSF:{
+               u8 btype_ibss = ((u8 *) (val))[0];
+
+               if (btype_ibss == true)
+                       _rtl8723ae_stop_tx_beacon(hw);
+
+               _rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(3));
+
+               rtl_write_dword(rtlpriv, REG_TSFTR,
+                               (u32) (mac->tsf & 0xffffffff));
+               rtl_write_dword(rtlpriv, REG_TSFTR + 4,
+                               (u32) ((mac->tsf >> 32) & 0xffffffff));
+
+               _rtl8723ae_set_bcn_ctrl_reg(hw, BIT(3), 0);
+
+               if (btype_ibss == true)
+                       _rtl8723ae_resume_tx_beacon(hw);
+               break; }
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not processed\n");
+               break;
+       }
+}
+
+static bool _rtl8723ae_llt_write(struct ieee80211_hw *hw, u32 address, u32 data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       bool status = true;
+       long count = 0;
+       u32 value = _LLT_INIT_ADDR(address) |
+           _LLT_INIT_DATA(data) | _LLT_OP(_LLT_WRITE_ACCESS);
+
+       rtl_write_dword(rtlpriv, REG_LLT_INIT, value);
+
+       do {
+               value = rtl_read_dword(rtlpriv, REG_LLT_INIT);
+               if (_LLT_NO_ACTIVE == _LLT_OP_VALUE(value))
+                       break;
+
+               if (count > POLLING_LLT_THRESHOLD) {
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "Failed to polling write LLT done at address %d!\n",
+                                address);
+                       status = false;
+                       break;
+               }
+       } while (++count);
+
+       return status;
+}
+
+static bool _rtl8723ae_llt_table_init(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       unsigned short i;
+       u8 txpktbuf_bndy;
+       u8 maxPage;
+       bool status;
+       u8 ubyte;
+
+       maxPage = 255;
+       txpktbuf_bndy = 246;
+
+       rtl_write_byte(rtlpriv, REG_CR, 0x8B);
+
+       rtl_write_word(rtlpriv, REG_RQPN_NPQ, 0x0000);
+
+       rtl_write_dword(rtlpriv, REG_RQPN, 0x80ac1c29);
+       rtl_write_byte(rtlpriv, REG_RQPN_NPQ, 0x03);
+
+       rtl_write_dword(rtlpriv, REG_TRXFF_BNDY, (0x27FF0000 | txpktbuf_bndy));
+       rtl_write_byte(rtlpriv, REG_TDECTRL + 1, txpktbuf_bndy);
+
+       rtl_write_byte(rtlpriv, REG_TXPKTBUF_BCNQ_BDNY, txpktbuf_bndy);
+       rtl_write_byte(rtlpriv, REG_TXPKTBUF_MGQ_BDNY, txpktbuf_bndy);
+
+       rtl_write_byte(rtlpriv, 0x45D, txpktbuf_bndy);
+       rtl_write_byte(rtlpriv, REG_PBP, 0x11);
+       rtl_write_byte(rtlpriv, REG_RX_DRVINFO_SZ, 0x4);
+
+       for (i = 0; i < (txpktbuf_bndy - 1); i++) {
+               status = _rtl8723ae_llt_write(hw, i, i + 1);
+               if (true != status)
+                       return status;
+       }
+
+       status = _rtl8723ae_llt_write(hw, (txpktbuf_bndy - 1), 0xFF);
+       if (true != status)
+               return status;
+
+       for (i = txpktbuf_bndy; i < maxPage; i++) {
+               status = _rtl8723ae_llt_write(hw, i, (i + 1));
+               if (true != status)
+                       return status;
+       }
+
+       status = _rtl8723ae_llt_write(hw, maxPage, txpktbuf_bndy);
+       if (true != status)
+               return status;
+
+       rtl_write_byte(rtlpriv, REG_CR, 0xff);
+       ubyte = rtl_read_byte(rtlpriv, REG_RQPN + 3);
+       rtl_write_byte(rtlpriv, REG_RQPN + 3, ubyte | BIT(7));
+
+       return true;
+}
+
+static void _rtl8723ae_gen_refresh_led_state(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+
+       if (rtlpriv->rtlhal.up_first_time)
+               return;
+
+       if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS)
+               rtl8723ae_sw_led_on(hw, pLed0);
+       else if (ppsc->rfoff_reason == RF_CHANGE_BY_INIT)
+               rtl8723ae_sw_led_on(hw, pLed0);
+       else
+               rtl8723ae_sw_led_off(hw, pLed0);
+}
+
+static bool _rtl8712e_init_mac(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       unsigned char bytetmp;
+       unsigned short wordtmp;
+       u16 retry = 0;
+       u16 tmpu2b;
+       bool mac_func_enable;
+
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x00);
+       bytetmp = rtl_read_byte(rtlpriv, REG_CR);
+       if (bytetmp == 0xFF)
+               mac_func_enable = true;
+       else
+               mac_func_enable = false;
+
+
+       /* HW Power on sequence */
+       if (!rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+               PWR_INTF_PCI_MSK, Rtl8723_NIC_ENABLE_FLOW))
+               return false;
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_PCIE_CTRL_REG+2);
+       rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG+2, bytetmp | BIT(4));
+
+       /* eMAC time out function enable, 0x369[7]=1 */
+       bytetmp = rtl_read_byte(rtlpriv, 0x369);
+       rtl_write_byte(rtlpriv, 0x369, bytetmp | BIT(7));
+
+       /* ePHY reg 0x1e bit[4]=1 using MDIO interface,
+        * we should do this before Enabling ASPM backdoor.
+        */
+       do {
+               rtl_write_word(rtlpriv, 0x358, 0x5e);
+               udelay(100);
+               rtl_write_word(rtlpriv, 0x356, 0xc280);
+               rtl_write_word(rtlpriv, 0x354, 0xc290);
+               rtl_write_word(rtlpriv, 0x358, 0x3e);
+               udelay(100);
+               rtl_write_word(rtlpriv, 0x358, 0x5e);
+               udelay(100);
+               tmpu2b = rtl_read_word(rtlpriv, 0x356);
+               retry++;
+       } while (tmpu2b != 0xc290 && retry < 100);
+
+       if (retry >= 100) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                        "InitMAC(): ePHY configure fail!!!\n");
+               return false;
+       }
+
+       rtl_write_word(rtlpriv, REG_CR, 0x2ff);
+       rtl_write_word(rtlpriv, REG_CR + 1, 0x06);
+
+       if (!mac_func_enable) {
+               if (_rtl8723ae_llt_table_init(hw) == false)
+                       return false;
+       }
+
+       rtl_write_dword(rtlpriv, REG_HISR, 0xffffffff);
+       rtl_write_byte(rtlpriv, REG_HISRE, 0xff);
+
+       rtl_write_word(rtlpriv, REG_TRXFF_BNDY + 2, 0x27ff);
+
+       wordtmp = rtl_read_word(rtlpriv, REG_TRXDMA_CTRL) & 0xf;
+       wordtmp |= 0xF771;
+       rtl_write_word(rtlpriv, REG_TRXDMA_CTRL, wordtmp);
+
+       rtl_write_byte(rtlpriv, REG_FWHW_TXQ_CTRL + 1, 0x1F);
+       rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+       rtl_write_word(rtlpriv, REG_RXFLTMAP2, 0xFFFF);
+       rtl_write_dword(rtlpriv, REG_TCR, rtlpci->transmit_config);
+
+       rtl_write_byte(rtlpriv, 0x4d0, 0x0);
+
+       rtl_write_dword(rtlpriv, REG_BCNQ_DESA,
+                       ((u64) rtlpci->tx_ring[BEACON_QUEUE].dma) &
+                       DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_MGQ_DESA,
+                       (u64) rtlpci->tx_ring[MGNT_QUEUE].dma &
+                       DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_VOQ_DESA,
+                       (u64) rtlpci->tx_ring[VO_QUEUE].dma & DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_VIQ_DESA,
+                       (u64) rtlpci->tx_ring[VI_QUEUE].dma & DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_BEQ_DESA,
+                       (u64) rtlpci->tx_ring[BE_QUEUE].dma & DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_BKQ_DESA,
+                       (u64) rtlpci->tx_ring[BK_QUEUE].dma & DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_HQ_DESA,
+                       (u64) rtlpci->tx_ring[HIGH_QUEUE].dma &
+                       DMA_BIT_MASK(32));
+       rtl_write_dword(rtlpriv, REG_RX_DESA,
+                       (u64) rtlpci->rx_ring[RX_MPDU_QUEUE].dma &
+                       DMA_BIT_MASK(32));
+
+       rtl_write_byte(rtlpriv, REG_PCIE_CTRL_REG + 3, 0x74);
+
+       rtl_write_dword(rtlpriv, REG_INT_MIG, 0);
+
+       bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
+       rtl_write_byte(rtlpriv, REG_APSD_CTRL, bytetmp & ~BIT(6));
+       do {
+               retry++;
+               bytetmp = rtl_read_byte(rtlpriv, REG_APSD_CTRL);
+       } while ((retry < 200) && (bytetmp & BIT(7)));
+
+       _rtl8723ae_gen_refresh_led_state(hw);
+
+       rtl_write_dword(rtlpriv, REG_MCUTST_1, 0x0);
+
+       return true;
+}
+
+static void _rtl8723ae_hw_configure(struct ieee80211_hw *hw)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       u8 reg_bw_opmode;
+       u32 reg_ratr, reg_prsr;
+
+       reg_bw_opmode = BW_OPMODE_20MHZ;
+       reg_ratr = RATE_ALL_CCK | RATE_ALL_OFDM_AG |
+           RATE_ALL_OFDM_1SS | RATE_ALL_OFDM_2SS;
+       reg_prsr = RATE_ALL_CCK | RATE_ALL_OFDM_AG;
+
+       rtl_write_byte(rtlpriv, REG_INIRTS_RATE_SEL, 0x8);
+
+       rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+
+       rtl_write_dword(rtlpriv, REG_RRSR, reg_prsr);
+
+       rtl_write_byte(rtlpriv, REG_SLOT, 0x09);
+
+       rtl_write_byte(rtlpriv, REG_AMPDU_MIN_SPACE, 0x0);
+
+       rtl_write_word(rtlpriv, REG_FWHW_TXQ_CTRL, 0x1F80);
+
+       rtl_write_word(rtlpriv, REG_RL, 0x0707);
+
+       rtl_write_dword(rtlpriv, REG_BAR_MODE_CTRL, 0x02012802);
+
+       rtl_write_byte(rtlpriv, REG_HWSEQ_CTRL, 0xFF);
+
+       rtl_write_dword(rtlpriv, REG_DARFRC, 0x01000000);
+       rtl_write_dword(rtlpriv, REG_DARFRC + 4, 0x07060504);
+       rtl_write_dword(rtlpriv, REG_RARFRC, 0x01000000);
+       rtl_write_dword(rtlpriv, REG_RARFRC + 4, 0x07060504);
+
+       if ((pcipriv->bt_coexist.bt_coexistence) &&
+           (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
+               rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0x97427431);
+       else
+               rtl_write_dword(rtlpriv, REG_AGGLEN_LMT, 0xb972a841);
+
+       rtl_write_byte(rtlpriv, REG_ATIMWND, 0x2);
+
+       rtl_write_byte(rtlpriv, REG_BCN_MAX_ERR, 0xff);
+
+       rtlpci->reg_bcn_ctrl_val = 0x1f;
+       rtl_write_byte(rtlpriv, REG_BCN_CTRL, rtlpci->reg_bcn_ctrl_val);
+
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+
+       rtl_write_byte(rtlpriv, REG_TBTT_PROHIBIT + 1, 0xff);
+
+       rtl_write_byte(rtlpriv, REG_PIFS, 0x1C);
+       rtl_write_byte(rtlpriv, REG_AGGR_BREAK_TIME, 0x16);
+
+       if ((pcipriv->bt_coexist.bt_coexistence) &&
+           (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4)) {
+               rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+               rtl_write_word(rtlpriv, REG_PROT_MODE_CTRL, 0x0402);
+       } else {
+               rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+               rtl_write_word(rtlpriv, REG_NAV_PROT_LEN, 0x0020);
+       }
+
+       if ((pcipriv->bt_coexist.bt_coexistence) &&
+            (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4))
+               rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x03086666);
+       else
+               rtl_write_dword(rtlpriv, REG_FAST_EDCA_CTRL, 0x086666);
+
+       rtl_write_byte(rtlpriv, REG_ACKTO, 0x40);
+
+       rtl_write_word(rtlpriv, REG_SPEC_SIFS, 0x1010);
+       rtl_write_word(rtlpriv, REG_MAC_SPEC_SIFS, 0x1010);
+
+       rtl_write_word(rtlpriv, REG_SIFS_CTX, 0x1010);
+
+       rtl_write_word(rtlpriv, REG_SIFS_TRX, 0x1010);
+
+       rtl_write_dword(rtlpriv, REG_MAR, 0xffffffff);
+       rtl_write_dword(rtlpriv, REG_MAR + 4, 0xffffffff);
+
+       rtl_write_dword(rtlpriv, 0x394, 0x1);
+}
+
+static void _rtl8723ae_enable_aspm_back_door(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       rtl_write_byte(rtlpriv, 0x34b, 0x93);
+       rtl_write_word(rtlpriv, 0x350, 0x870c);
+       rtl_write_byte(rtlpriv, 0x352, 0x1);
+
+       if (ppsc->support_backdoor)
+               rtl_write_byte(rtlpriv, 0x349, 0x1b);
+       else
+               rtl_write_byte(rtlpriv, 0x349, 0x03);
+
+       rtl_write_word(rtlpriv, 0x350, 0x2718);
+       rtl_write_byte(rtlpriv, 0x352, 0x1);
+}
+
+void rtl8723ae_enable_hw_security_config(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 sec_reg_value;
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                "PairwiseEncAlgorithm = %d GroupEncAlgorithm = %d\n",
+                rtlpriv->sec.pairwise_enc_algorithm,
+                rtlpriv->sec.group_enc_algorithm);
+
+       if (rtlpriv->cfg->mod_params->sw_crypto || rtlpriv->sec.use_sw_sec) {
+               RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                        "not open hw encryption\n");
+               return;
+       }
+
+       sec_reg_value = SCR_TxEncEnable | SCR_RxDecEnable;
+
+       if (rtlpriv->sec.use_defaultkey) {
+               sec_reg_value |= SCR_TxUseDK;
+               sec_reg_value |= SCR_RxUseDK;
+       }
+
+       sec_reg_value |= (SCR_RXBCUSEDK | SCR_TXBCUSEDK);
+
+       rtl_write_byte(rtlpriv, REG_CR + 1, 0x02);
+
+       RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                "The SECR-value %x\n", sec_reg_value);
+
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_WPA_CONFIG, &sec_reg_value);
+
+}
+
+int rtl8723ae_hw_init(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       bool rtstatus = true;
+       int err;
+       u8 tmp_u1b;
+
+       rtlpriv->rtlhal.being_init_adapter = true;
+       rtlpriv->intf_ops->disable_aspm(hw);
+       rtstatus = _rtl8712e_init_mac(hw);
+       if (rtstatus != true) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Init MAC failed\n");
+               err = 1;
+               return err;
+       }
+
+       err = rtl8723ae_download_fw(hw);
+       if (err) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "Failed to download FW. Init HW without FW now..\n");
+               err = 1;
+               rtlhal->fw_ready = false;
+               return err;
+       } else {
+               rtlhal->fw_ready = true;
+       }
+
+       rtlhal->last_hmeboxnum = 0;
+       rtl8723ae_phy_mac_config(hw);
+       /* because the last function modifies RCR, we update
+        * rcr var here, or TP will be unstable as ther receive_config
+        * is wrong, RX RCR_ACRC32 will cause TP unstable & Rx
+        * RCR_APP_ICV will cause mac80211 unassoc for cisco 1252
+        */
+       rtlpci->receive_config = rtl_read_dword(rtlpriv, REG_RCR);
+       rtlpci->receive_config &= ~(RCR_ACRC32 | RCR_AICV);
+       rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+       rtl8723ae_phy_bb_config(hw);
+       rtlphy->rf_mode = RF_OP_BY_SW_3WIRE;
+       rtl8723ae_phy_rf_config(hw);
+       if (IS_VENDOR_UMC_A_CUT(rtlhal->version)) {
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD, 0x30255);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G2, MASKDWORD, 0x50a00);
+       } else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x0C, MASKDWORD, 0x894AE);
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x0A, MASKDWORD, 0x1AF31);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_IPA, MASKDWORD, 0x8F425);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_SYN_G2, MASKDWORD, 0x4F200);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK1, MASKDWORD, 0x44053);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_RCK2, MASKDWORD, 0x80201);
+       }
+       rtlphy->rfreg_chnlval[0] = rtl_get_rfreg(hw, (enum radio_path)0,
+                                                RF_CHNLBW, RFREG_OFFSET_MASK);
+       rtlphy->rfreg_chnlval[1] = rtl_get_rfreg(hw, (enum radio_path)1,
+                                                RF_CHNLBW, RFREG_OFFSET_MASK);
+       rtl_set_bbreg(hw, RFPGA0_RFMOD, BCCKEN, 0x1);
+       rtl_set_bbreg(hw, RFPGA0_RFMOD, BOFDMEN, 0x1);
+       rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
+       _rtl8723ae_hw_configure(hw);
+       rtl_cam_reset_all_entry(hw);
+       rtl8723ae_enable_hw_security_config(hw);
+
+       ppsc->rfpwr_state = ERFON;
+
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_ETHER_ADDR, mac->mac_addr);
+       _rtl8723ae_enable_aspm_back_door(hw);
+       rtlpriv->intf_ops->enable_aspm(hw);
+
+       rtl8723ae_bt_hw_init(hw);
+
+       if (ppsc->rfpwr_state == ERFON) {
+               rtl8723ae_phy_set_rfpath_switch(hw, 1);
+               if (rtlphy->iqk_initialized) {
+                       rtl8723ae_phy_iq_calibrate(hw, true);
+               } else {
+                       rtl8723ae_phy_iq_calibrate(hw, false);
+                       rtlphy->iqk_initialized = true;
+               }
+
+               rtl8723ae_phy_lc_calibrate(hw);
+       }
+
+       tmp_u1b = efuse_read_1byte(hw, 0x1FA);
+       if (!(tmp_u1b & BIT(0))) {
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x15, 0x0F, 0x05);
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "PA BIAS path A\n");
+       }
+
+       if (!(tmp_u1b & BIT(4))) {
+               tmp_u1b = rtl_read_byte(rtlpriv, 0x16) & 0x0F;
+               rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x80);
+               udelay(10);
+               rtl_write_byte(rtlpriv, 0x16, tmp_u1b | 0x90);
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "under 1.5V\n");
+       }
+       rtl8723ae_dm_init(hw);
+       rtlpriv->rtlhal.being_init_adapter = false;
+       return err;
+}
+
+static enum version_8723e _rtl8723ae_read_chip_version(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       enum version_8723e version = 0x0000;
+       u32 value32;
+
+       value32 = rtl_read_dword(rtlpriv, REG_SYS_CFG);
+       if (value32 & TRP_VAUX_EN) {
+               version = (enum version_8723e)(version |
+                         ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0));
+               /* RTL8723 with BT function. */
+               version = (enum version_8723e)(version |
+                         ((value32 & BT_FUNC) ? CHIP_8723 : 0));
+
+       } else {
+               /* Normal mass production chip. */
+               version = (enum version_8723e) NORMAL_CHIP;
+               version = (enum version_8723e)(version |
+                         ((value32 & VENDOR_ID) ? CHIP_VENDOR_UMC : 0));
+               /* RTL8723 with BT function. */
+               version = (enum version_8723e)(version |
+                         ((value32 & BT_FUNC) ? CHIP_8723 : 0));
+               if (IS_CHIP_VENDOR_UMC(version))
+                       version = (enum version_8723e)(version |
+                       ((value32 & CHIP_VER_RTL_MASK)));/* IC version (CUT) */
+               if (IS_8723_SERIES(version)) {
+                       value32 = rtl_read_dword(rtlpriv, REG_GPIO_OUTSTS);
+                       /* ROM code version */
+                       version = (enum version_8723e)(version |
+                                 ((value32 & RF_RL_ID)>>20));
+               }
+       }
+
+       if (IS_8723_SERIES(version)) {
+               value32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL);
+               rtlphy->polarity_ctl = ((value32 & WL_HWPDN_SL) ?
+                                      RT_POLARITY_HIGH_ACT :
+                                      RT_POLARITY_LOW_ACT);
+       }
+       switch (version) {
+       case VERSION_TEST_UMC_CHIP_8723:
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Chip Version ID: VERSION_TEST_UMC_CHIP_8723.\n");
+               break;
+       case VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT:
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Chip Version ID: VERSION_NORMAL_UMC_CHIP_8723_1T1R_A_CUT.\n");
+               break;
+       case VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT:
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Chip Version ID: VERSION_NORMAL_UMC_CHIP_8723_1T1R_B_CUT.\n");
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Chip Version ID: Unknown. Bug?\n");
+               break;
+       }
+
+       if (IS_8723_SERIES(version))
+               rtlphy->rf_type = RF_1T1R;
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Chip RF Type: %s\n",
+               (rtlphy->rf_type == RF_2T2R) ? "RF_2T2R" : "RF_1T1R");
+
+       return version;
+}
+
+static int _rtl8723ae_set_media_status(struct ieee80211_hw *hw,
+                                    enum nl80211_iftype type)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 bt_msr = rtl_read_byte(rtlpriv, MSR) & 0xfc;
+       enum led_ctl_mode ledaction = LED_CTL_NO_LINK;
+
+       rtl_write_dword(rtlpriv, REG_BCN_CTRL, 0);
+       RT_TRACE(rtlpriv, COMP_BEACON, DBG_LOUD,
+                "clear 0x550 when set HW_VAR_MEDIA_STATUS\n");
+
+       if (type == NL80211_IFTYPE_UNSPECIFIED ||
+           type == NL80211_IFTYPE_STATION) {
+               _rtl8723ae_stop_tx_beacon(hw);
+               _rtl8723ae_enable_bcn_sufunc(hw);
+       } else if (type == NL80211_IFTYPE_ADHOC ||
+               type == NL80211_IFTYPE_AP) {
+               _rtl8723ae_resume_tx_beacon(hw);
+               _rtl8723ae_disable_bcn_sufunc(hw);
+       } else {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "Set HW_VAR_MEDIA_STATUS: No such media status(%x).\n",
+                        type);
+       }
+
+       switch (type) {
+       case NL80211_IFTYPE_UNSPECIFIED:
+               bt_msr |= MSR_NOLINK;
+               ledaction = LED_CTL_LINK;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Set Network type to NO LINK!\n");
+               break;
+       case NL80211_IFTYPE_ADHOC:
+               bt_msr |= MSR_ADHOC;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Set Network type to Ad Hoc!\n");
+               break;
+       case NL80211_IFTYPE_STATION:
+               bt_msr |= MSR_INFRA;
+               ledaction = LED_CTL_LINK;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Set Network type to STA!\n");
+               break;
+       case NL80211_IFTYPE_AP:
+               bt_msr |= MSR_AP;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "Set Network type to AP!\n");
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Network type %d not supported!\n",
+                        type);
+               return 1;
+               break;
+
+       }
+
+       rtl_write_byte(rtlpriv, (MSR), bt_msr);
+       rtlpriv->cfg->ops->led_control(hw, ledaction);
+       if ((bt_msr & 0x03) == MSR_AP)
+               rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x00);
+       else
+               rtl_write_byte(rtlpriv, REG_BCNTCFG + 1, 0x66);
+       return 0;
+}
+
+void rtl8723ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       u32 reg_rcr = rtlpci->receive_config;
+
+       if (rtlpriv->psc.rfpwr_state != ERFON)
+               return;
+
+       if (check_bssid == true) {
+               reg_rcr |= (RCR_CBSSID_DATA | RCR_CBSSID_BCN);
+               rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_RCR,
+                                             (u8 *)(&reg_rcr));
+               _rtl8723ae_set_bcn_ctrl_reg(hw, 0, BIT(4));
+       } else if (check_bssid == false) {
+               reg_rcr &= (~(RCR_CBSSID_DATA | RCR_CBSSID_BCN));
+               _rtl8723ae_set_bcn_ctrl_reg(hw, BIT(4), 0);
+               rtlpriv->cfg->ops->set_hw_reg(hw,
+                       HW_VAR_RCR, (u8 *) (&reg_rcr));
+       }
+}
+
+int rtl8723ae_set_network_type(struct ieee80211_hw *hw,
+                              enum nl80211_iftype type)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (_rtl8723ae_set_media_status(hw, type))
+               return -EOPNOTSUPP;
+
+       if (rtlpriv->mac80211.link_state == MAC80211_LINKED) {
+               if (type != NL80211_IFTYPE_AP)
+                       rtl8723ae_set_check_bssid(hw, true);
+       } else {
+               rtl8723ae_set_check_bssid(hw, false);
+       }
+       return 0;
+}
+
+/* don't set REG_EDCA_BE_PARAM here because mac80211 will send pkt when scan */
+void rtl8723ae_set_qos(struct ieee80211_hw *hw, int aci)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtl8723ae_dm_init_edca_turbo(hw);
+       switch (aci) {
+       case AC1_BK:
+               rtl_write_dword(rtlpriv, REG_EDCA_BK_PARAM, 0xa44f);
+               break;
+       case AC0_BE:
+               /* rtl_write_dword(rtlpriv, REG_EDCA_BE_PARAM, u4ac_param); */
+               break;
+       case AC2_VI:
+               rtl_write_dword(rtlpriv, REG_EDCA_VI_PARAM, 0x5e4322);
+               break;
+       case AC3_VO:
+               rtl_write_dword(rtlpriv, REG_EDCA_VO_PARAM, 0x2f3222);
+               break;
+       default:
+               RT_ASSERT(false, "invalid aci: %d !\n", aci);
+               break;
+       }
+}
+
+void rtl8723ae_enable_interrupt(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       rtl_write_dword(rtlpriv, 0x3a8, rtlpci->irq_mask[0] & 0xFFFFFFFF);
+       rtl_write_dword(rtlpriv, 0x3ac, rtlpci->irq_mask[1] & 0xFFFFFFFF);
+       rtlpci->irq_enabled = true;
+}
+
+void rtl8723ae_disable_interrupt(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       rtl_write_dword(rtlpriv, 0x3a8, IMR8190_DISABLED);
+       rtl_write_dword(rtlpriv, 0x3ac, IMR8190_DISABLED);
+       rtlpci->irq_enabled = false;
+       synchronize_irq(rtlpci->pdev->irq);
+}
+
+static void _rtl8723ae_poweroff_adapter(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 u1tmp;
+
+       /* Combo (PCIe + USB) Card and PCIe-MF Card */
+       /* 1. Run LPS WL RFOFF flow */
+       rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+               PWR_INTF_PCI_MSK, Rtl8723_NIC_LPS_ENTER_FLOW);
+
+       /* 2. 0x1F[7:0] = 0 */
+       /* turn off RF */
+       rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x00);
+       if ((rtl_read_byte(rtlpriv, REG_MCUFWDL) & BIT(7)) && rtlhal->fw_ready)
+               rtl8723ae_firmware_selfreset(hw);
+
+       /* Reset MCU. Suggested by Filen. */
+       u1tmp = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN+1);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN+1, (u1tmp & (~BIT(2))));
+
+       /* g.   MCUFWDL 0x80[1:0]=0      */
+       /* reset MCU ready status */
+       rtl_write_byte(rtlpriv, REG_MCUFWDL, 0x00);
+
+       /* HW card disable configuration. */
+       rtl_hal_pwrseqcmdparsing(rtlpriv, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,
+               PWR_INTF_PCI_MSK, Rtl8723_NIC_DISABLE_FLOW);
+
+       /* Reset MCU IO Wrapper */
+       u1tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, (u1tmp & (~BIT(0))));
+       u1tmp = rtl_read_byte(rtlpriv, REG_RSV_CTRL + 1);
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL + 1, u1tmp | BIT(0));
+
+       /* 7. RSV_CTRL 0x1C[7:0] = 0x0E */
+       /* lock ISO/CLK/Power control register */
+       rtl_write_byte(rtlpriv, REG_RSV_CTRL, 0x0e);
+}
+
+void rtl8723ae_card_disable(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       enum nl80211_iftype opmode;
+
+       mac->link_state = MAC80211_NOLINK;
+       opmode = NL80211_IFTYPE_UNSPECIFIED;
+       _rtl8723ae_set_media_status(hw, opmode);
+       if (rtlpci->driver_is_goingto_unload ||
+           ppsc->rfoff_reason > RF_CHANGE_BY_PS)
+               rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
+       RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+       _rtl8723ae_poweroff_adapter(hw);
+
+       /* after power off we should do iqk again */
+       rtlpriv->phy.iqk_initialized = false;
+}
+
+void rtl8723ae_interrupt_recognized(struct ieee80211_hw *hw,
+                                   u32 *p_inta, u32 *p_intb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       *p_inta = rtl_read_dword(rtlpriv, 0x3a0) & rtlpci->irq_mask[0];
+       rtl_write_dword(rtlpriv, 0x3a0, *p_inta);
+}
+
+void rtl8723ae_set_beacon_related_registers(struct ieee80211_hw *hw)
+{
+
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u16 bcn_interval, atim_window;
+
+       bcn_interval = mac->beacon_interval;
+       atim_window = 2;        /*FIX MERGE */
+       rtl8723ae_disable_interrupt(hw);
+       rtl_write_word(rtlpriv, REG_ATIMWND, atim_window);
+       rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+       rtl_write_word(rtlpriv, REG_BCNTCFG, 0x660f);
+       rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_CCK, 0x18);
+       rtl_write_byte(rtlpriv, REG_RXTSF_OFFSET_OFDM, 0x18);
+       rtl_write_byte(rtlpriv, 0x606, 0x30);
+       rtl8723ae_enable_interrupt(hw);
+}
+
+void rtl8723ae_set_beacon_interval(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u16 bcn_interval = mac->beacon_interval;
+
+       RT_TRACE(rtlpriv, COMP_BEACON, DBG_DMESG,
+                "beacon_interval:%d\n", bcn_interval);
+       rtl8723ae_disable_interrupt(hw);
+       rtl_write_word(rtlpriv, REG_BCN_INTERVAL, bcn_interval);
+       rtl8723ae_enable_interrupt(hw);
+}
+
+void rtl8723ae_update_interrupt_mask(struct ieee80211_hw *hw,
+                                    u32 add_msr, u32 rm_msr)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       RT_TRACE(rtlpriv, COMP_INTR, DBG_LOUD,
+                "add_msr:%x, rm_msr:%x\n", add_msr, rm_msr);
+
+       if (add_msr)
+               rtlpci->irq_mask[0] |= add_msr;
+       if (rm_msr)
+               rtlpci->irq_mask[0] &= (~rm_msr);
+       rtl8723ae_disable_interrupt(hw);
+       rtl8723ae_enable_interrupt(hw);
+}
+
+static u8 _rtl8723ae_get_chnl_group(u8 chnl)
+{
+       u8 group;
+
+       if (chnl < 3)
+               group = 0;
+       else if (chnl < 9)
+               group = 1;
+       else
+               group = 2;
+       return group;
+}
+
+static void _rtl8723ae_read_txpower_info_from_hwpg(struct ieee80211_hw *hw,
+                                                  bool autoload_fail,
+                                                  u8 *hwinfo)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 rf_path, index, tempval;
+       u16 i;
+
+       for (rf_path = 0; rf_path < 1; rf_path++) {
+               for (i = 0; i < 3; i++) {
+                       if (!autoload_fail) {
+                               rtlefuse->eeprom_chnlarea_txpwr_cck
+                                   [rf_path][i] =
+                                   hwinfo[EEPROM_TXPOWERCCK + rf_path * 3 + i];
+                               rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+                                   [rf_path][i] =
+                                   hwinfo[EEPROM_TXPOWERHT40_1S + rf_path *
+                                   3 + i];
+                       } else {
+                               rtlefuse->eeprom_chnlarea_txpwr_cck
+                                   [rf_path][i] =
+                                   EEPROM_DEFAULT_TXPOWERLEVEL;
+                               rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+                                   [rf_path][i] =
+                                   EEPROM_DEFAULT_TXPOWERLEVEL;
+                       }
+               }
+       }
+
+       for (i = 0; i < 3; i++) {
+               if (!autoload_fail)
+                       tempval = hwinfo[EEPROM_TXPOWERHT40_2SDIFF + i];
+               else
+                       tempval = EEPROM_DEFAULT_HT40_2SDIFF;
+               rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_A][i] =
+                   (tempval & 0xf);
+               rtlefuse->eprom_chnl_txpwr_ht40_2sdf[RF90_PATH_B][i] =
+                   ((tempval & 0xf0) >> 4);
+       }
+
+       for (rf_path = 0; rf_path < 2; rf_path++)
+               for (i = 0; i < 3; i++)
+                       RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+                               "RF(%d) EEPROM CCK Area(%d) = 0x%x\n", rf_path,
+                               i, rtlefuse->eeprom_chnlarea_txpwr_cck
+                               [rf_path][i]);
+       for (rf_path = 0; rf_path < 2; rf_path++)
+               for (i = 0; i < 3; i++)
+                       RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+                               "RF(%d) EEPROM HT40 1S Area(%d) = 0x%x\n",
+                               rf_path, i,
+                               rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+                               [rf_path][i]);
+       for (rf_path = 0; rf_path < 2; rf_path++)
+               for (i = 0; i < 3; i++)
+                       RTPRINT(rtlpriv, FINIT, INIT_EEPROM,
+                               "RF(%d) EEPROM HT40 2S Diff Area(%d) = 0x%x\n",
+                               rf_path, i,
+                               rtlefuse->eprom_chnl_txpwr_ht40_2sdf
+                               [rf_path][i]);
+
+       for (rf_path = 0; rf_path < 2; rf_path++) {
+               for (i = 0; i < 14; i++) {
+                       index = _rtl8723ae_get_chnl_group((u8) i);
+
+                       rtlefuse->txpwrlevel_cck[rf_path][i] =
+                               rtlefuse->eeprom_chnlarea_txpwr_cck
+                                                       [rf_path][index];
+                       rtlefuse->txpwrlevel_ht40_1s[rf_path][i] =
+                               rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+                                                       [rf_path][index];
+
+                       if ((rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+                           [rf_path][index] -
+                           rtlefuse->eprom_chnl_txpwr_ht40_2sdf[rf_path]
+                           [index]) > 0) {
+                               rtlefuse->txpwrlevel_ht40_2s[rf_path][i] =
+                                       rtlefuse->eeprom_chnlarea_txpwr_ht40_1s
+                                       [rf_path][index] -
+                                       rtlefuse->eprom_chnl_txpwr_ht40_2sdf
+                                       [rf_path][index];
+                       } else {
+                               rtlefuse->txpwrlevel_ht40_2s[rf_path][i] = 0;
+                       }
+               }
+
+               for (i = 0; i < 14; i++) {
+                       RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+                               "RF(%d)-Ch(%d) [CCK / HT40_1S / HT40_2S] = "
+                               "[0x%x / 0x%x / 0x%x]\n", rf_path, i,
+                               rtlefuse->txpwrlevel_cck[rf_path][i],
+                               rtlefuse->txpwrlevel_ht40_1s[rf_path][i],
+                               rtlefuse->txpwrlevel_ht40_2s[rf_path][i]);
+               }
+       }
+
+       for (i = 0; i < 3; i++) {
+               if (!autoload_fail) {
+                       rtlefuse->eeprom_pwrlimit_ht40[i] =
+                           hwinfo[EEPROM_TXPWR_GROUP + i];
+                       rtlefuse->eeprom_pwrlimit_ht20[i] =
+                           hwinfo[EEPROM_TXPWR_GROUP + 3 + i];
+               } else {
+                       rtlefuse->eeprom_pwrlimit_ht40[i] = 0;
+                       rtlefuse->eeprom_pwrlimit_ht20[i] = 0;
+               }
+       }
+
+       for (rf_path = 0; rf_path < 2; rf_path++) {
+               for (i = 0; i < 14; i++) {
+                       index = _rtl8723ae_get_chnl_group((u8) i);
+
+                       if (rf_path == RF90_PATH_A) {
+                               rtlefuse->pwrgroup_ht20[rf_path][i] =
+                                   (rtlefuse->eeprom_pwrlimit_ht20[index] &
+                                   0xf);
+                               rtlefuse->pwrgroup_ht40[rf_path][i] =
+                                   (rtlefuse->eeprom_pwrlimit_ht40[index] &
+                                   0xf);
+                       } else if (rf_path == RF90_PATH_B) {
+                               rtlefuse->pwrgroup_ht20[rf_path][i] =
+                                   ((rtlefuse->eeprom_pwrlimit_ht20[index] &
+                                   0xf0) >> 4);
+                               rtlefuse->pwrgroup_ht40[rf_path][i] =
+                                   ((rtlefuse->eeprom_pwrlimit_ht40[index] &
+                                   0xf0) >> 4);
+                       }
+
+                       RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+                               "RF-%d pwrgroup_ht20[%d] = 0x%x\n", rf_path, i,
+                               rtlefuse->pwrgroup_ht20[rf_path][i]);
+                       RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+                               "RF-%d pwrgroup_ht40[%d] = 0x%x\n", rf_path, i,
+                               rtlefuse->pwrgroup_ht40[rf_path][i]);
+               }
+       }
+
+       for (i = 0; i < 14; i++) {
+               index = _rtl8723ae_get_chnl_group((u8) i);
+
+               if (!autoload_fail)
+                       tempval = hwinfo[EEPROM_TXPOWERHT20DIFF + index];
+               else
+                       tempval = EEPROM_DEFAULT_HT20_DIFF;
+
+               rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] = (tempval & 0xF);
+               rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] =
+                   ((tempval >> 4) & 0xF);
+
+               if (rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] & BIT(3))
+                       rtlefuse->txpwr_ht20diff[RF90_PATH_A][i] |= 0xF0;
+
+               if (rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] & BIT(3))
+                       rtlefuse->txpwr_ht20diff[RF90_PATH_B][i] |= 0xF0;
+
+               index = _rtl8723ae_get_chnl_group((u8) i);
+
+               if (!autoload_fail)
+                       tempval = hwinfo[EEPROM_TXPOWER_OFDMDIFF + index];
+               else
+                       tempval = EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF;
+
+               rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i] = (tempval & 0xF);
+               rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i] =
+                   ((tempval >> 4) & 0xF);
+       }
+
+       rtlefuse->legacy_ht_txpowerdiff =
+           rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][7];
+
+       for (i = 0; i < 14; i++)
+               RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+                       "RF-A Ht20 to HT40 Diff[%d] = 0x%x\n", i,
+                       rtlefuse->txpwr_ht20diff[RF90_PATH_A][i]);
+       for (i = 0; i < 14; i++)
+               RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+                       "RF-A Legacy to Ht40 Diff[%d] = 0x%x\n", i,
+                       rtlefuse->txpwr_legacyhtdiff[RF90_PATH_A][i]);
+       for (i = 0; i < 14; i++)
+               RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+                       "RF-B Ht20 to HT40 Diff[%d] = 0x%x\n", i,
+                       rtlefuse->txpwr_ht20diff[RF90_PATH_B][i]);
+       for (i = 0; i < 14; i++)
+               RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+                       "RF-B Legacy to HT40 Diff[%d] = 0x%x\n", i,
+                       rtlefuse->txpwr_legacyhtdiff[RF90_PATH_B][i]);
+
+       if (!autoload_fail)
+               rtlefuse->eeprom_regulatory = (hwinfo[RF_OPTION1] & 0x7);
+       else
+               rtlefuse->eeprom_regulatory = 0;
+       RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+               "eeprom_regulatory = 0x%x\n", rtlefuse->eeprom_regulatory);
+
+       if (!autoload_fail)
+               rtlefuse->eeprom_tssi[RF90_PATH_A] = hwinfo[EEPROM_TSSI_A];
+       else
+               rtlefuse->eeprom_tssi[RF90_PATH_A] = EEPROM_DEFAULT_TSSI;
+       RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+               "TSSI_A = 0x%x, TSSI_B = 0x%x\n",
+               rtlefuse->eeprom_tssi[RF90_PATH_A],
+               rtlefuse->eeprom_tssi[RF90_PATH_B]);
+
+       if (!autoload_fail)
+               tempval = hwinfo[EEPROM_THERMAL_METER];
+       else
+               tempval = EEPROM_DEFAULT_THERMALMETER;
+       rtlefuse->eeprom_thermalmeter = (tempval & 0x1f);
+
+       if (rtlefuse->eeprom_thermalmeter == 0x1f || autoload_fail)
+               rtlefuse->apk_thermalmeterignore = true;
+
+       rtlefuse->thermalmeter[0] = rtlefuse->eeprom_thermalmeter;
+       RTPRINT(rtlpriv, FINIT, INIT_TxPower,
+               "thermalmeter = 0x%x\n", rtlefuse->eeprom_thermalmeter);
+}
+
+static void _rtl8723ae_read_adapter_info(struct ieee80211_hw *hw,
+                                        bool pseudo_test)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u16 i, usvalue;
+       u8 hwinfo[HWSET_MAX_SIZE];
+       u16 eeprom_id;
+
+       if (pseudo_test) {
+               /* need add */
+               return;
+       }
+       if (rtlefuse->epromtype == EEPROM_BOOT_EFUSE) {
+               rtl_efuse_shadow_map_update(hw);
+
+               memcpy(hwinfo, &rtlefuse->efuse_map[EFUSE_INIT_MAP][0],
+                      HWSET_MAX_SIZE);
+       } else if (rtlefuse->epromtype == EEPROM_93C46) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "RTL819X Not boot from eeprom, check it !!");
+       }
+
+       RT_PRINT_DATA(rtlpriv, COMP_INIT, DBG_DMESG, ("MAP\n"),
+                     hwinfo, HWSET_MAX_SIZE);
+
+       eeprom_id = *((u16 *)&hwinfo[0]);
+       if (eeprom_id != RTL8190_EEPROM_ID) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "EEPROM ID(%#x) is invalid!!\n", eeprom_id);
+               rtlefuse->autoload_failflag = true;
+       } else {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+               rtlefuse->autoload_failflag = false;
+       }
+
+       if (rtlefuse->autoload_failflag == true)
+               return;
+
+       rtlefuse->eeprom_vid = *(u16 *) &hwinfo[EEPROM_VID];
+       rtlefuse->eeprom_did = *(u16 *) &hwinfo[EEPROM_DID];
+       rtlefuse->eeprom_svid = *(u16 *) &hwinfo[EEPROM_SVID];
+       rtlefuse->eeprom_smid = *(u16 *) &hwinfo[EEPROM_SMID];
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROMId = 0x%4x\n", eeprom_id);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM VID = 0x%4x\n", rtlefuse->eeprom_vid);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM DID = 0x%4x\n", rtlefuse->eeprom_did);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM SVID = 0x%4x\n", rtlefuse->eeprom_svid);
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM SMID = 0x%4x\n", rtlefuse->eeprom_smid);
+
+       for (i = 0; i < 6; i += 2) {
+               usvalue = *(u16 *)&hwinfo[EEPROM_MAC_ADDR + i];
+               *((u16 *) (&rtlefuse->dev_addr[i])) = usvalue;
+       }
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                "dev_addr: %pM\n", rtlefuse->dev_addr);
+
+       _rtl8723ae_read_txpower_info_from_hwpg(hw,
+                       rtlefuse->autoload_failflag, hwinfo);
+
+       rtl8723ae_read_bt_coexist_info_from_hwpg(hw,
+                       rtlefuse->autoload_failflag, hwinfo);
+
+       rtlefuse->eeprom_channelplan = *(u8 *)&hwinfo[EEPROM_CHANNELPLAN];
+       rtlefuse->eeprom_version = *(u16 *)&hwinfo[EEPROM_VERSION];
+       rtlefuse->txpwr_fromeprom = true;
+       rtlefuse->eeprom_oemid = *(u8 *)&hwinfo[EEPROM_CUSTOMER_ID];
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                "EEPROM Customer ID: 0x%2x\n", rtlefuse->eeprom_oemid);
+
+       /* set channel paln to world wide 13 */
+       rtlefuse->channel_plan = COUNTRY_CODE_WORLD_WIDE_13;
+
+       if (rtlhal->oem_id == RT_CID_DEFAULT) {
+               switch (rtlefuse->eeprom_oemid) {
+               case EEPROM_CID_DEFAULT:
+                       if (rtlefuse->eeprom_did == 0x8176) {
+                               if (CHK_SVID_SMID(0x10EC, 0x6151) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6152) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6154) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6155) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6177) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6178) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6179) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6180) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8151) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8152) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8154) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8155) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8181) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8182) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8184) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8185) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9151) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9152) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9154) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9155) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9181) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9182) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9184) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9185))
+                                       rtlhal->oem_id = RT_CID_TOSHIBA;
+                               else if (rtlefuse->eeprom_svid == 0x1025)
+                                       rtlhal->oem_id = RT_CID_819x_Acer;
+                               else if (CHK_SVID_SMID(0x10EC, 0x6191) ||
+                                        CHK_SVID_SMID(0x10EC, 0x6192) ||
+                                        CHK_SVID_SMID(0x10EC, 0x6193) ||
+                                        CHK_SVID_SMID(0x10EC, 0x7191) ||
+                                        CHK_SVID_SMID(0x10EC, 0x7192) ||
+                                        CHK_SVID_SMID(0x10EC, 0x7193) ||
+                                        CHK_SVID_SMID(0x10EC, 0x8191) ||
+                                        CHK_SVID_SMID(0x10EC, 0x8192) ||
+                                        CHK_SVID_SMID(0x10EC, 0x8193))
+                                       rtlhal->oem_id = RT_CID_819x_SAMSUNG;
+                               else if (CHK_SVID_SMID(0x10EC, 0x8195) ||
+                                        CHK_SVID_SMID(0x10EC, 0x9195) ||
+                                        CHK_SVID_SMID(0x10EC, 0x7194) ||
+                                        CHK_SVID_SMID(0x10EC, 0x8200) ||
+                                        CHK_SVID_SMID(0x10EC, 0x8201) ||
+                                        CHK_SVID_SMID(0x10EC, 0x8202) ||
+                                        CHK_SVID_SMID(0x10EC, 0x9200))
+                                       rtlhal->oem_id = RT_CID_819x_Lenovo;
+                               else if (CHK_SVID_SMID(0x10EC, 0x8197) ||
+                                        CHK_SVID_SMID(0x10EC, 0x9196))
+                                       rtlhal->oem_id = RT_CID_819x_CLEVO;
+                               else if (CHK_SVID_SMID(0x1028, 0x8194) ||
+                                        CHK_SVID_SMID(0x1028, 0x8198) ||
+                                        CHK_SVID_SMID(0x1028, 0x9197) ||
+                                        CHK_SVID_SMID(0x1028, 0x9198))
+                                       rtlhal->oem_id = RT_CID_819x_DELL;
+                               else if (CHK_SVID_SMID(0x103C, 0x1629))
+                                       rtlhal->oem_id = RT_CID_819x_HP;
+                               else if (CHK_SVID_SMID(0x1A32, 0x2315))
+                                       rtlhal->oem_id = RT_CID_819x_QMI;
+                               else if (CHK_SVID_SMID(0x10EC, 0x8203))
+                                       rtlhal->oem_id = RT_CID_819x_PRONETS;
+                               else if (CHK_SVID_SMID(0x1043, 0x84B5))
+                                       rtlhal->oem_id =
+                                                RT_CID_819x_Edimax_ASUS;
+                               else
+                                       rtlhal->oem_id = RT_CID_DEFAULT;
+                       } else if (rtlefuse->eeprom_did == 0x8178) {
+                               if (CHK_SVID_SMID(0x10EC, 0x6181) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6182) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6184) ||
+                                   CHK_SVID_SMID(0x10EC, 0x6185) ||
+                                   CHK_SVID_SMID(0x10EC, 0x7181) ||
+                                   CHK_SVID_SMID(0x10EC, 0x7182) ||
+                                   CHK_SVID_SMID(0x10EC, 0x7184) ||
+                                   CHK_SVID_SMID(0x10EC, 0x7185) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8181) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8182) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8184) ||
+                                   CHK_SVID_SMID(0x10EC, 0x8185) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9181) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9182) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9184) ||
+                                   CHK_SVID_SMID(0x10EC, 0x9185))
+                                       rtlhal->oem_id = RT_CID_TOSHIBA;
+                               else if (rtlefuse->eeprom_svid == 0x1025)
+                                       rtlhal->oem_id = RT_CID_819x_Acer;
+                               else if (CHK_SVID_SMID(0x10EC, 0x8186))
+                                       rtlhal->oem_id = RT_CID_819x_PRONETS;
+                               else if (CHK_SVID_SMID(0x1043, 0x8486))
+                                       rtlhal->oem_id =
+                                                    RT_CID_819x_Edimax_ASUS;
+                               else
+                                       rtlhal->oem_id = RT_CID_DEFAULT;
+                       } else {
+                                       rtlhal->oem_id = RT_CID_DEFAULT;
+                       }
+                       break;
+               case EEPROM_CID_TOSHIBA:
+                       rtlhal->oem_id = RT_CID_TOSHIBA;
+                       break;
+               case EEPROM_CID_CCX:
+                       rtlhal->oem_id = RT_CID_CCX;
+                       break;
+               case EEPROM_CID_QMI:
+                       rtlhal->oem_id = RT_CID_819x_QMI;
+                       break;
+               case EEPROM_CID_WHQL:
+                               break;
+               default:
+                       rtlhal->oem_id = RT_CID_DEFAULT;
+                       break;
+
+               }
+       }
+}
+
+static void _rtl8723ae_hal_customized_behavior(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       switch (rtlhal->oem_id) {
+       case RT_CID_819x_HP:
+               pcipriv->ledctl.led_opendrain = true;
+               break;
+       case RT_CID_819x_Lenovo:
+       case RT_CID_DEFAULT:
+       case RT_CID_TOSHIBA:
+       case RT_CID_CCX:
+       case RT_CID_819x_Acer:
+       case RT_CID_WHQL:
+       default:
+               break;
+       }
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                "RT Customized ID: 0x%02X\n", rtlhal->oem_id);
+}
+
+void rtl8723ae_read_eeprom_info(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 tmp_u1b;
+       u32 value32;
+
+       value32 = rtl_read_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST]);
+       value32 = (value32 & ~EFUSE_SEL_MASK) | EFUSE_SEL(EFUSE_WIFI_SEL_0);
+       rtl_write_dword(rtlpriv, rtlpriv->cfg->maps[EFUSE_TEST], value32);
+
+       rtlhal->version = _rtl8723ae_read_chip_version(hw);
+
+       if (get_rf_type(rtlphy) == RF_1T1R)
+               rtlpriv->dm.rfpath_rxenable[0] = true;
+       else
+               rtlpriv->dm.rfpath_rxenable[0] =
+                   rtlpriv->dm.rfpath_rxenable[1] = true;
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "VersionID = 0x%4x\n",
+                rtlhal->version);
+
+       tmp_u1b = rtl_read_byte(rtlpriv, REG_9346CR);
+       if (tmp_u1b & BIT(4)) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EEPROM\n");
+               rtlefuse->epromtype = EEPROM_93C46;
+       } else {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "Boot from EFUSE\n");
+               rtlefuse->epromtype = EEPROM_BOOT_EFUSE;
+       }
+       if (tmp_u1b & BIT(5)) {
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "Autoload OK\n");
+               rtlefuse->autoload_failflag = false;
+               _rtl8723ae_read_adapter_info(hw, false);
+       } else {
+               rtlefuse->autoload_failflag = true;
+               _rtl8723ae_read_adapter_info(hw, false);
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Autoload ERR!!\n");
+       }
+       _rtl8723ae_hal_customized_behavior(hw);
+}
+
+static void rtl8723ae_update_hal_rate_table(struct ieee80211_hw *hw,
+                                           struct ieee80211_sta *sta)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u32 ratr_value;
+       u8 ratr_index = 0;
+       u8 nmode = mac->ht_enable;
+       u8 mimo_ps = IEEE80211_SMPS_OFF;
+       u8 curtxbw_40mhz = mac->bw_40;
+       u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+                               1 : 0;
+       u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+                               1 : 0;
+       enum wireless_mode wirelessmode = mac->mode;
+
+       if (rtlhal->current_bandtype == BAND_ON_5G)
+               ratr_value = sta->supp_rates[1] << 4;
+       else
+               ratr_value = sta->supp_rates[0];
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               ratr_value = 0xfff;
+       ratr_value |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+                      sta->ht_cap.mcs.rx_mask[0] << 12);
+       switch (wirelessmode) {
+       case WIRELESS_MODE_B:
+               if (ratr_value & 0x0000000c)
+                       ratr_value &= 0x0000000d;
+               else
+                       ratr_value &= 0x0000000f;
+               break;
+       case WIRELESS_MODE_G:
+               ratr_value &= 0x00000FF5;
+               break;
+       case WIRELESS_MODE_N_24G:
+       case WIRELESS_MODE_N_5G:
+               nmode = 1;
+               if (mimo_ps == IEEE80211_SMPS_STATIC) {
+                       ratr_value &= 0x0007F005;
+               } else {
+                       u32 ratr_mask;
+
+                       if (get_rf_type(rtlphy) == RF_1T2R ||
+                           get_rf_type(rtlphy) == RF_1T1R)
+                               ratr_mask = 0x000ff005;
+                       else
+                               ratr_mask = 0x0f0ff005;
+
+                       ratr_value &= ratr_mask;
+               }
+               break;
+       default:
+               if (rtlphy->rf_type == RF_1T2R)
+                       ratr_value &= 0x000ff0ff;
+               else
+                       ratr_value &= 0x0f0ff0ff;
+
+               break;
+       }
+
+       if ((pcipriv->bt_coexist.bt_coexistence) &&
+           (pcipriv->bt_coexist.bt_coexist_type == BT_CSR_BC4) &&
+           (pcipriv->bt_coexist.bt_cur_state) &&
+           (pcipriv->bt_coexist.bt_ant_isolation) &&
+           ((pcipriv->bt_coexist.bt_service == BT_SCO) ||
+           (pcipriv->bt_coexist.bt_service == BT_BUSY)))
+               ratr_value &= 0x0fffcfc0;
+       else
+               ratr_value &= 0x0FFFFFFF;
+
+       if (nmode && ((curtxbw_40mhz && curshortgi_40mhz) ||
+          (!curtxbw_40mhz && curshortgi_20mhz)))
+               ratr_value |= 0x10000000;
+
+       rtl_write_dword(rtlpriv, REG_ARFR0 + ratr_index * 4, ratr_value);
+
+       RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+                "%x\n", rtl_read_dword(rtlpriv, REG_ARFR0));
+}
+
+static void rtl8723ae_update_hal_rate_mask(struct ieee80211_hw *hw,
+               struct ieee80211_sta *sta, u8 rssi_level)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_sta_info *sta_entry = NULL;
+       u32 ratr_bitmap;
+       u8 ratr_index;
+       u8 curtxbw_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40)
+                               ? 1 : 0;
+       u8 curshortgi_40mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_40) ?
+                               1 : 0;
+       u8 curshortgi_20mhz = (sta->ht_cap.cap & IEEE80211_HT_CAP_SGI_20) ?
+                               1 : 0;
+       enum wireless_mode wirelessmode = 0;
+       bool shortgi = false;
+       u8 rate_mask[5];
+       u8 macid = 0;
+       u8 mimo_ps = IEEE80211_SMPS_OFF;
+
+       sta_entry = (struct rtl_sta_info *) sta->drv_priv;
+       wirelessmode = sta_entry->wireless_mode;
+       if (mac->opmode == NL80211_IFTYPE_STATION)
+               curtxbw_40mhz = mac->bw_40;
+       else if (mac->opmode == NL80211_IFTYPE_AP ||
+               mac->opmode == NL80211_IFTYPE_ADHOC)
+               macid = sta->aid + 1;
+
+       if (rtlhal->current_bandtype == BAND_ON_5G)
+               ratr_bitmap = sta->supp_rates[1] << 4;
+       else
+               ratr_bitmap = sta->supp_rates[0];
+       if (mac->opmode == NL80211_IFTYPE_ADHOC)
+               ratr_bitmap = 0xfff;
+       ratr_bitmap |= (sta->ht_cap.mcs.rx_mask[1] << 20 |
+                       sta->ht_cap.mcs.rx_mask[0] << 12);
+       switch (wirelessmode) {
+       case WIRELESS_MODE_B:
+               ratr_index = RATR_INX_WIRELESS_B;
+               if (ratr_bitmap & 0x0000000c)
+                       ratr_bitmap &= 0x0000000d;
+               else
+                       ratr_bitmap &= 0x0000000f;
+               break;
+       case WIRELESS_MODE_G:
+               ratr_index = RATR_INX_WIRELESS_GB;
+
+               if (rssi_level == 1)
+                       ratr_bitmap &= 0x00000f00;
+               else if (rssi_level == 2)
+                       ratr_bitmap &= 0x00000ff0;
+               else
+                       ratr_bitmap &= 0x00000ff5;
+               break;
+       case WIRELESS_MODE_A:
+               ratr_index = RATR_INX_WIRELESS_A;
+               ratr_bitmap &= 0x00000ff0;
+               break;
+       case WIRELESS_MODE_N_24G:
+       case WIRELESS_MODE_N_5G:
+               ratr_index = RATR_INX_WIRELESS_NGB;
+
+               if (mimo_ps == IEEE80211_SMPS_STATIC) {
+                       if (rssi_level == 1)
+                               ratr_bitmap &= 0x00070000;
+                       else if (rssi_level == 2)
+                               ratr_bitmap &= 0x0007f000;
+                       else
+                               ratr_bitmap &= 0x0007f005;
+               } else {
+                       if (rtlphy->rf_type == RF_1T2R ||
+                           rtlphy->rf_type == RF_1T1R) {
+                               if (curtxbw_40mhz) {
+                                       if (rssi_level == 1)
+                                               ratr_bitmap &= 0x000f0000;
+                                       else if (rssi_level == 2)
+                                               ratr_bitmap &= 0x000ff000;
+                                       else
+                                               ratr_bitmap &= 0x000ff015;
+                               } else {
+                                       if (rssi_level == 1)
+                                               ratr_bitmap &= 0x000f0000;
+                                       else if (rssi_level == 2)
+                                               ratr_bitmap &= 0x000ff000;
+                                       else
+                                               ratr_bitmap &= 0x000ff005;
+                               }
+                       } else {
+                               if (curtxbw_40mhz) {
+                                       if (rssi_level == 1)
+                                               ratr_bitmap &= 0x0f0f0000;
+                                       else if (rssi_level == 2)
+                                               ratr_bitmap &= 0x0f0ff000;
+                                       else
+                                               ratr_bitmap &= 0x0f0ff015;
+                               } else {
+                                       if (rssi_level == 1)
+                                               ratr_bitmap &= 0x0f0f0000;
+                                       else if (rssi_level == 2)
+                                               ratr_bitmap &= 0x0f0ff000;
+                                       else
+                                               ratr_bitmap &= 0x0f0ff005;
+                               }
+                       }
+               }
+
+               if ((curtxbw_40mhz && curshortgi_40mhz) ||
+                   (!curtxbw_40mhz && curshortgi_20mhz)) {
+                       if (macid == 0)
+                               shortgi = true;
+                       else if (macid == 1)
+                               shortgi = false;
+               }
+               break;
+       default:
+               ratr_index = RATR_INX_WIRELESS_NGB;
+
+               if (rtlphy->rf_type == RF_1T2R)
+                       ratr_bitmap &= 0x000ff0ff;
+               else
+                       ratr_bitmap &= 0x0f0ff0ff;
+               break;
+       }
+       sta_entry->ratr_index = ratr_index;
+
+       RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+                "ratr_bitmap :%x\n", ratr_bitmap);
+       /* convert ratr_bitmap to le byte array */
+       rate_mask[0] = ratr_bitmap;
+       rate_mask[1] = (ratr_bitmap >>= 8);
+       rate_mask[2] = (ratr_bitmap >>= 8);
+       rate_mask[3] = ((ratr_bitmap >> 8) & 0x0f) | (ratr_index << 4);
+       rate_mask[4] = macid | (shortgi ? 0x20 : 0x00) | 0x80;
+       RT_TRACE(rtlpriv, COMP_RATR, DBG_DMESG,
+                "Rate_index:%x, ratr_bitmap: %*phC\n",
+                ratr_index, 5, rate_mask);
+       rtl8723ae_fill_h2c_cmd(hw, H2C_RA_MASK, 5, rate_mask);
+}
+
+void rtl8723ae_update_hal_rate_tbl(struct ieee80211_hw *hw,
+               struct ieee80211_sta *sta, u8 rssi_level)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->dm.useramask)
+               rtl8723ae_update_hal_rate_mask(hw, sta, rssi_level);
+       else
+               rtl8723ae_update_hal_rate_table(hw, sta);
+}
+
+void rtl8723ae_update_channel_access_setting(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u16 sifs_timer;
+
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SLOT_TIME,
+                                     (u8 *)&mac->slot_time);
+       if (!mac->ht_enable)
+               sifs_timer = 0x0a0a;
+       else
+               sifs_timer = 0x1010;
+       rtlpriv->cfg->ops->set_hw_reg(hw, HW_VAR_SIFS, (u8 *)&sifs_timer);
+}
+
+bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       enum rf_pwrstate e_rfpowerstate_toset, cur_rfstate;
+       u8 u1tmp;
+       bool actuallyset = false;
+
+       if (rtlpriv->rtlhal.being_init_adapter)
+               return false;
+
+       if (ppsc->swrf_processing)
+               return false;
+
+       spin_lock(&rtlpriv->locks.rf_ps_lock);
+       if (ppsc->rfchange_inprogress) {
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+               return false;
+       } else {
+               ppsc->rfchange_inprogress = true;
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+       }
+
+       cur_rfstate = ppsc->rfpwr_state;
+
+       rtl_write_byte(rtlpriv, REG_GPIO_IO_SEL_2,
+                      rtl_read_byte(rtlpriv, REG_GPIO_IO_SEL_2)&~(BIT(1)));
+
+       u1tmp = rtl_read_byte(rtlpriv, REG_GPIO_PIN_CTRL_2);
+
+       if (rtlphy->polarity_ctl)
+               e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFOFF : ERFON;
+       else
+               e_rfpowerstate_toset = (u1tmp & BIT(1)) ? ERFON : ERFOFF;
+
+       if ((ppsc->hwradiooff == true) && (e_rfpowerstate_toset == ERFON)) {
+               RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                        "GPIOChangeRF  - HW Radio ON, RF ON\n");
+
+               e_rfpowerstate_toset = ERFON;
+               ppsc->hwradiooff = false;
+               actuallyset = true;
+       } else if ((ppsc->hwradiooff == false)
+                  && (e_rfpowerstate_toset == ERFOFF)) {
+               RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                        "GPIOChangeRF  - HW Radio OFF, RF OFF\n");
+
+               e_rfpowerstate_toset = ERFOFF;
+               ppsc->hwradiooff = true;
+               actuallyset = true;
+       }
+
+       if (actuallyset) {
+               spin_lock(&rtlpriv->locks.rf_ps_lock);
+               ppsc->rfchange_inprogress = false;
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+       } else {
+               if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC)
+                       RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+
+               spin_lock(&rtlpriv->locks.rf_ps_lock);
+               ppsc->rfchange_inprogress = false;
+               spin_unlock(&rtlpriv->locks.rf_ps_lock);
+       }
+
+       *valid = 1;
+       return !ppsc->hwradiooff;
+}
+
+void rtl8723ae_set_key(struct ieee80211_hw *hw, u32 key_index,
+                      u8 *p_macaddr, bool is_group, u8 enc_algo,
+                      bool is_wepkey, bool clear_all)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 *macaddr = p_macaddr;
+       u32 entry_id = 0;
+       bool is_pairwise = false;
+       static u8 cam_const_addr[4][6] = {
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x00},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x01},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x02},
+               {0x00, 0x00, 0x00, 0x00, 0x00, 0x03}
+       };
+       static u8 cam_const_broad[] = {
+               0xff, 0xff, 0xff, 0xff, 0xff, 0xff
+       };
+
+       if (clear_all) {
+               u8 idx = 0;
+               u8 cam_offset = 0;
+               u8 clear_number = 5;
+
+               RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG, "clear_all\n");
+
+               for (idx = 0; idx < clear_number; idx++) {
+                       rtl_cam_mark_invalid(hw, cam_offset + idx);
+                       rtl_cam_empty_entry(hw, cam_offset + idx);
+
+                       if (idx < 5) {
+                               memset(rtlpriv->sec.key_buf[idx], 0,
+                                      MAX_KEY_LEN);
+                               rtlpriv->sec.key_len[idx] = 0;
+                       }
+               }
+       } else {
+               switch (enc_algo) {
+               case WEP40_ENCRYPTION:
+                       enc_algo = CAM_WEP40;
+                       break;
+               case WEP104_ENCRYPTION:
+                       enc_algo = CAM_WEP104;
+                       break;
+               case TKIP_ENCRYPTION:
+                       enc_algo = CAM_TKIP;
+                       break;
+               case AESCCMP_ENCRYPTION:
+                       enc_algo = CAM_AES;
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not processed\n");
+                       enc_algo = CAM_TKIP;
+                       break;
+               }
+
+               if (is_wepkey || rtlpriv->sec.use_defaultkey) {
+                       macaddr = cam_const_addr[key_index];
+                       entry_id = key_index;
+               } else {
+                       if (is_group) {
+                               macaddr = cam_const_broad;
+                               entry_id = key_index;
+                       } else {
+                               if (mac->opmode == NL80211_IFTYPE_AP) {
+                                       entry_id = rtl_cam_get_free_entry(hw,
+                                                               macaddr);
+                                       if (entry_id >=  TOTAL_CAM_ENTRY) {
+                                               RT_TRACE(rtlpriv, COMP_SEC,
+                                                        DBG_EMERG,
+                                                        "Can not find free hw security cam entry\n");
+                                               return;
+                                       }
+                               } else {
+                                       entry_id = CAM_PAIRWISE_KEY_POSITION;
+                               }
+
+                               key_index = PAIRWISE_KEYIDX;
+                               is_pairwise = true;
+                       }
+               }
+
+               if (rtlpriv->sec.key_len[key_index] == 0) {
+                       RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                                "delete one entry, entry_id is %d\n",
+                                entry_id);
+                       if (mac->opmode == NL80211_IFTYPE_AP)
+                               rtl_cam_del_entry(hw, p_macaddr);
+                       rtl_cam_delete_one_entry(hw, p_macaddr, entry_id);
+               } else {
+                       RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                                "add one entry\n");
+                       if (is_pairwise) {
+                               RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                                        "set Pairwiase key\n");
+
+                               rtl_cam_add_one_entry(hw, macaddr, key_index,
+                                       entry_id, enc_algo,
+                                       CAM_CONFIG_NO_USEDK,
+                                       rtlpriv->sec.key_buf[key_index]);
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_SEC, DBG_DMESG,
+                                        "set group key\n");
+
+                               if (mac->opmode == NL80211_IFTYPE_ADHOC) {
+                                       rtl_cam_add_one_entry(hw,
+                                               rtlefuse->dev_addr,
+                                               PAIRWISE_KEYIDX,
+                                               CAM_PAIRWISE_KEY_POSITION,
+                                               enc_algo,
+                                               CAM_CONFIG_NO_USEDK,
+                                               rtlpriv->sec.key_buf
+                                               [entry_id]);
+                               }
+
+                               rtl_cam_add_one_entry(hw, macaddr, key_index,
+                                               entry_id, enc_algo,
+                                               CAM_CONFIG_NO_USEDK,
+                                               rtlpriv->sec.key_buf[entry_id]);
+                       }
+
+               }
+       }
+}
+
+static void rtl8723ae_bt_var_init(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       pcipriv->bt_coexist.bt_coexistence =
+                                       pcipriv->bt_coexist.eeprom_bt_coexist;
+       pcipriv->bt_coexist.bt_ant_num =
+                                       pcipriv->bt_coexist.eeprom_bt_ant_num;
+       pcipriv->bt_coexist.bt_coexist_type =
+                                       pcipriv->bt_coexist.eeprom_bt_type;
+
+               pcipriv->bt_coexist.bt_ant_isolation =
+                               pcipriv->bt_coexist.eeprom_bt_ant_isol;
+
+       pcipriv->bt_coexist.bt_radio_shared_type =
+                               pcipriv->bt_coexist.eeprom_bt_radio_shared;
+
+       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                "BT Coexistance = 0x%x\n",
+                pcipriv->bt_coexist.bt_coexistence);
+
+       if (pcipriv->bt_coexist.bt_coexistence) {
+               pcipriv->bt_coexist.bt_busy_traffic = false;
+               pcipriv->bt_coexist.bt_traffic_mode_set = false;
+               pcipriv->bt_coexist.bt_non_traffic_mode_set = false;
+
+               pcipriv->bt_coexist.cstate = 0;
+               pcipriv->bt_coexist.previous_state = 0;
+
+               if (pcipriv->bt_coexist.bt_ant_num == ANT_X2) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "BlueTooth BT_Ant_Num = Antx2\n");
+               } else if (pcipriv->bt_coexist.bt_ant_num == ANT_X1) {
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "BlueTooth BT_Ant_Num = Antx1\n");
+               }
+
+               switch (pcipriv->bt_coexist.bt_coexist_type) {
+               case BT_2WIRE:
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "BlueTooth BT_CoexistType = BT_2Wire\n");
+                       break;
+               case BT_ISSC_3WIRE:
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "BlueTooth BT_CoexistType = BT_ISSC_3Wire\n");
+                       break;
+               case BT_ACCEL:
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "BlueTooth BT_CoexistType = BT_ACCEL\n");
+                       break;
+               case BT_CSR_BC4:
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "BlueTooth BT_CoexistType = BT_CSR_BC4\n");
+                       break;
+               case BT_CSR_BC8:
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "BlueTooth BT_CoexistType = BT_CSR_BC8\n");
+                       break;
+               case BT_RTL8756:
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "BlueTooth BT_CoexistType = BT_RTL8756\n");
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                                "BlueTooth BT_CoexistType = Unknown\n");
+                       break;
+               }
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "BlueTooth BT_Ant_isolation = %d\n",
+                        pcipriv->bt_coexist.bt_ant_isolation);
+               RT_TRACE(rtlpriv, COMP_BT_COEXIST, DBG_TRACE,
+                        "BT_RadioSharedType = 0x%x\n",
+                        pcipriv->bt_coexist.bt_radio_shared_type);
+               pcipriv->bt_coexist.bt_active_zero_cnt = 0;
+               pcipriv->bt_coexist.cur_bt_disabled = false;
+               pcipriv->bt_coexist.pre_bt_disabled = false;
+       }
+}
+
+void rtl8723ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+                                             bool auto_load_fail, u8 *hwinfo)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 value;
+       u32 tmpu_32;
+
+       if (!auto_load_fail) {
+               tmpu_32 = rtl_read_dword(rtlpriv, REG_MULTI_FUNC_CTRL);
+               if (tmpu_32 & BIT(18))
+                       pcipriv->bt_coexist.eeprom_bt_coexist = 1;
+               else
+                       pcipriv->bt_coexist.eeprom_bt_coexist = 0;
+               value = hwinfo[RF_OPTION4];
+               pcipriv->bt_coexist.eeprom_bt_type = BT_RTL8723A;
+               pcipriv->bt_coexist.eeprom_bt_ant_num = (value & 0x1);
+               pcipriv->bt_coexist.eeprom_bt_ant_isol = ((value & 0x10) >> 4);
+               pcipriv->bt_coexist.eeprom_bt_radio_shared =
+                               ((value & 0x20) >> 5);
+       } else {
+               pcipriv->bt_coexist.eeprom_bt_coexist = 0;
+               pcipriv->bt_coexist.eeprom_bt_type = BT_RTL8723A;
+               pcipriv->bt_coexist.eeprom_bt_ant_num = ANT_X2;
+               pcipriv->bt_coexist.eeprom_bt_ant_isol = 0;
+               pcipriv->bt_coexist.eeprom_bt_radio_shared = BT_RADIO_SHARED;
+       }
+
+       rtl8723ae_bt_var_init(hw);
+}
+
+void rtl8723ae_bt_reg_init(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+
+       /* 0:Low, 1:High, 2:From Efuse. */
+       pcipriv->bt_coexist.reg_bt_iso = 2;
+       /* 0:Idle, 1:None-SCO, 2:SCO, 3:From Counter. */
+       pcipriv->bt_coexist.reg_bt_sco = 3;
+       /* 0:Disable BT control A-MPDU, 1:Enable BT control A-MPDU. */
+       pcipriv->bt_coexist.reg_bt_sco = 0;
+}
+
+
+void rtl8723ae_bt_hw_init(struct ieee80211_hw *hw)
+{
+}
+
+void rtl8723ae_suspend(struct ieee80211_hw *hw)
+{
+}
+
+void rtl8723ae_resume(struct ieee80211_hw *hw)
+{
+}
+
+/* Turn on AAP (RCR:bit 0) for promicuous mode. */
+void rtl8723ae_allow_all_destaddr(struct ieee80211_hw *hw,
+       bool allow_all_da, bool write_into_reg)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       if (allow_all_da) /* Set BIT0 */
+               rtlpci->receive_config |= RCR_AAP;
+       else /* Clear BIT0 */
+               rtlpci->receive_config &= ~RCR_AAP;
+
+       if (write_into_reg)
+               rtl_write_dword(rtlpriv, REG_RCR, rtlpci->receive_config);
+
+
+       RT_TRACE(rtlpriv, COMP_TURBO | COMP_INIT, DBG_LOUD,
+                "receive_config=0x%08X, write_into_reg=%d\n",
+                rtlpci->receive_config, write_into_reg);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/hw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/hw.h
new file mode 100644 (file)
index 0000000..6fa24f7
--- /dev/null
@@ -0,0 +1,73 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_HW_H__
+#define __RTL8723E_HW_H__
+
+#define CHK_SVID_SMID(_val1, _val2)                            \
+       ((rtlefuse->eeprom_svid == (_val1)) &&                  \
+        (rtlefuse->eeprom_smid == (_val2)))
+
+void rtl8723ae_get_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8723ae_read_eeprom_info(struct ieee80211_hw *hw);
+
+void rtl8723ae_interrupt_recognized(struct ieee80211_hw *hw,
+                                   u32 *p_inta, u32 *p_intb);
+int rtl8723ae_hw_init(struct ieee80211_hw *hw);
+void rtl8723ae_card_disable(struct ieee80211_hw *hw);
+void rtl8723ae_enable_interrupt(struct ieee80211_hw *hw);
+void rtl8723ae_disable_interrupt(struct ieee80211_hw *hw);
+int rtl8723ae_set_network_type(struct ieee80211_hw *hw,
+                              enum nl80211_iftype type);
+void rtl8723ae_set_check_bssid(struct ieee80211_hw *hw, bool check_bssid);
+void rtl8723ae_set_qos(struct ieee80211_hw *hw, int aci);
+void rtl8723ae_set_beacon_related_registers(struct ieee80211_hw *hw);
+void rtl8723ae_set_beacon_interval(struct ieee80211_hw *hw);
+void rtl8723ae_update_interrupt_mask(struct ieee80211_hw *hw,
+                                    u32 add_msr, u32 rm_msr);
+void rtl8723ae_set_hw_reg(struct ieee80211_hw *hw, u8 variable, u8 *val);
+void rtl8723ae_update_hal_rate_tbl(struct ieee80211_hw *hw,
+                                  struct ieee80211_sta *sta, u8 rssi_level);
+void rtl8723ae_update_channel_access_setting(struct ieee80211_hw *hw);
+bool rtl8723ae_gpio_radio_on_off_checking(struct ieee80211_hw *hw, u8 *valid);
+void rtl8723ae_enable_hw_security_config(struct ieee80211_hw *hw);
+void rtl8723ae_set_key(struct ieee80211_hw *hw, u32 key_index,
+                      u8 *p_macaddr, bool is_group, u8 enc_algo,
+                      bool is_wepkey, bool clear_all);
+
+void rtl8723ae_read_bt_coexist_info_from_hwpg(struct ieee80211_hw *hw,
+                                             bool autoload_fail, u8 *hwinfo);
+void rtl8723ae_bt_reg_init(struct ieee80211_hw *hw);
+void rtl8723ae_bt_hw_init(struct ieee80211_hw *hw);
+void rtl8723ae_suspend(struct ieee80211_hw *hw);
+void rtl8723ae_resume(struct ieee80211_hw *hw);
+void rtl8723ae_allow_all_destaddr(struct ieee80211_hw *hw,
+                                 bool allow_all_da, bool write_into_reg);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/led.c b/drivers/net/wireless/rtlwifi/rtl8723ae/led.c
new file mode 100644 (file)
index 0000000..9c4e1d8
--- /dev/null
@@ -0,0 +1,151 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "reg.h"
+#include "led.h"
+
+static void _rtl8723ae_init_led(struct ieee80211_hw *hw,
+                               struct rtl_led *pled, enum rtl_led_pin ledpin)
+{
+       pled->hw = hw;
+       pled->ledpin = ledpin;
+       pled->ledon = false;
+}
+
+void rtl8723ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 ledcfg;
+
+       RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+                "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
+
+       ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+
+       switch (pled->ledpin) {
+       case LED_PIN_GPIO0:
+               break;
+       case LED_PIN_LED0:
+               rtl_write_byte(rtlpriv,
+                              REG_LEDCFG2, (ledcfg & 0xf0) | BIT(5) | BIT(6));
+               break;
+       case LED_PIN_LED1:
+               rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg & 0x0f) | BIT(5));
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not processed\n");
+               break;
+       }
+       pled->ledon = true;
+}
+
+void rtl8723ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       u8 ledcfg;
+
+       RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD,
+                "LedAddr:%X ledpin=%d\n", REG_LEDCFG2, pled->ledpin);
+
+       ledcfg = rtl_read_byte(rtlpriv, REG_LEDCFG2);
+
+       switch (pled->ledpin) {
+       case LED_PIN_GPIO0:
+               break;
+       case LED_PIN_LED0:
+               ledcfg &= 0xf0;
+               if (pcipriv->ledctl.led_opendrain)
+                       rtl_write_byte(rtlpriv, REG_LEDCFG2,
+                                      (ledcfg | BIT(1) | BIT(5) | BIT(6)));
+               else
+                       rtl_write_byte(rtlpriv, REG_LEDCFG2,
+                                      (ledcfg | BIT(3) | BIT(5) | BIT(6)));
+               break;
+       case LED_PIN_LED1:
+               ledcfg &= 0x0f;
+               rtl_write_byte(rtlpriv, REG_LEDCFG2, (ledcfg | BIT(3)));
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not processed\n");
+               break;
+       }
+       pled->ledon = false;
+}
+
+void rtl8723ae_init_sw_leds(struct ieee80211_hw *hw)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+
+       _rtl8723ae_init_led(hw, &(pcipriv->ledctl.sw_led0), LED_PIN_LED0);
+       _rtl8723ae_init_led(hw, &(pcipriv->ledctl.sw_led1), LED_PIN_LED1);
+}
+
+static void _rtl8723ae_sw_led_control(struct ieee80211_hw *hw,
+                                   enum led_ctl_mode ledaction)
+{
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_led *pLed0 = &(pcipriv->ledctl.sw_led0);
+
+       switch (ledaction) {
+       case LED_CTL_POWER_ON:
+       case LED_CTL_LINK:
+       case LED_CTL_NO_LINK:
+               rtl8723ae_sw_led_on(hw, pLed0);
+               break;
+       case LED_CTL_POWER_OFF:
+               rtl8723ae_sw_led_off(hw, pLed0);
+               break;
+       default:
+               break;
+       }
+}
+
+void rtl8723ae_led_control(struct ieee80211_hw *hw, enum led_ctl_mode ledaction)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+
+       if ((ppsc->rfoff_reason > RF_CHANGE_BY_PS) &&
+           (ledaction == LED_CTL_TX ||
+            ledaction == LED_CTL_RX ||
+            ledaction == LED_CTL_SITE_SURVEY ||
+            ledaction == LED_CTL_LINK ||
+            ledaction == LED_CTL_NO_LINK ||
+            ledaction == LED_CTL_START_TO_LINK ||
+            ledaction == LED_CTL_POWER_ON)) {
+               return;
+       }
+       RT_TRACE(rtlpriv, COMP_LED, DBG_LOUD, "ledaction %d,\n", ledaction);
+       _rtl8723ae_sw_led_control(hw, ledaction);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/led.h b/drivers/net/wireless/rtlwifi/rtl8723ae/led.h
new file mode 100644 (file)
index 0000000..2cb88e7
--- /dev/null
@@ -0,0 +1,39 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92CE_LED_H__
+#define __RTL92CE_LED_H__
+
+void rtl8723ae_init_sw_leds(struct ieee80211_hw *hw);
+void rtl8723ae_sw_led_on(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8723ae_sw_led_off(struct ieee80211_hw *hw, struct rtl_led *pled);
+void rtl8723ae_led_control(struct ieee80211_hw *hw,
+                          enum led_ctl_mode ledaction);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.c
new file mode 100644 (file)
index 0000000..39cc793
--- /dev/null
@@ -0,0 +1,2044 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../ps.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+#include "table.h"
+
+/* static forward definitions */
+static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw,
+                                 enum radio_path rfpath, u32 offset);
+static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw,
+                                   enum radio_path rfpath,
+                                   u32 offset, u32 data);
+static u32 _phy_rf_serial_read(struct ieee80211_hw *hw,
+                              enum radio_path rfpath, u32 offset);
+static void _phy_rf_serial_write(struct ieee80211_hw *hw,
+                                enum radio_path rfpath, u32 offset, u32 data);
+static u32 _phy_calculate_bit_shift(u32 bitmask);
+static bool _phy_bb8192c_config_parafile(struct ieee80211_hw *hw);
+static bool _phy_cfg_mac_w_header(struct ieee80211_hw *hw);
+static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype);
+static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype);
+static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw);
+static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+                                     u32 cmdtableidx, u32 cmdtablesz,
+                                     enum swchnlcmd_id cmdid,
+                                     u32 para1, u32 para2,
+                                     u32 msdelay);
+static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
+                                     u8 *stage, u8 *step, u32 *delay);
+static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
+                               enum wireless_mode wirelessmode,
+                               long power_indbm);
+static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+                                 enum wireless_mode wirelessmode, u8 txpwridx);
+static void rtl8723ae_phy_set_io(struct ieee80211_hw *hw);
+
+u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw, u32 regaddr,
+                              u32 bitmask)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 returnvalue, originalvalue, bitshift;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x)\n", regaddr, bitmask);
+       originalvalue = rtl_read_dword(rtlpriv, regaddr);
+       bitshift = _phy_calculate_bit_shift(bitmask);
+       returnvalue = (originalvalue & bitmask) >> bitshift;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "BBR MASK=0x%x Addr[0x%x]=0x%x\n", bitmask, regaddr,
+                originalvalue);
+
+       return returnvalue;
+}
+
+void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw,
+                             u32 regaddr, u32 bitmask, u32 data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 originalvalue, bitshift;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x), data(%#x)\n", regaddr,
+                bitmask, data);
+
+       if (bitmask != MASKDWORD) {
+               originalvalue = rtl_read_dword(rtlpriv, regaddr);
+               bitshift = _phy_calculate_bit_shift(bitmask);
+               data = ((originalvalue & (~bitmask)) | (data << bitshift));
+       }
+
+       rtl_write_dword(rtlpriv, regaddr, data);
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x), data(%#x)\n",
+                regaddr, bitmask, data);
+}
+
+u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
+                              enum radio_path rfpath, u32 regaddr, u32 bitmask)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 original_value, readback_value, bitshift;
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       unsigned long flags;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), rfpath(%#x), bitmask(%#x)\n",
+                regaddr, rfpath, bitmask);
+
+       spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+       if (rtlphy->rf_mode != RF_OP_BY_FW)
+               original_value = _phy_rf_serial_read(hw, rfpath, regaddr);
+       else
+               original_value = _phy_fw_rf_serial_read(hw, rfpath, regaddr);
+
+       bitshift = _phy_calculate_bit_shift(bitmask);
+       readback_value = (original_value & bitmask) >> bitshift;
+
+       spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), rfpath(%#x), bitmask(%#x), original_value(%#x)\n",
+                regaddr, rfpath, bitmask, original_value);
+
+       return readback_value;
+}
+
+void rtl8723ae_phy_set_rf_reg(struct ieee80211_hw *hw,
+                             enum radio_path rfpath,
+                             u32 regaddr, u32 bitmask, u32 data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u32 original_value, bitshift;
+       unsigned long flags;
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+                regaddr, bitmask, data, rfpath);
+
+       spin_lock_irqsave(&rtlpriv->locks.rf_lock, flags);
+
+       if (rtlphy->rf_mode != RF_OP_BY_FW) {
+               if (bitmask != RFREG_OFFSET_MASK) {
+                       original_value = _phy_rf_serial_read(hw, rfpath,
+                                                            regaddr);
+                       bitshift = _phy_calculate_bit_shift(bitmask);
+                       data = ((original_value & (~bitmask)) |
+                              (data << bitshift));
+               }
+
+               _phy_rf_serial_write(hw, rfpath, regaddr, data);
+       } else {
+               if (bitmask != RFREG_OFFSET_MASK) {
+                       original_value = _phy_fw_rf_serial_read(hw, rfpath,
+                                                               regaddr);
+                       bitshift = _phy_calculate_bit_shift(bitmask);
+                       data = ((original_value & (~bitmask)) |
+                              (data << bitshift));
+               }
+               _phy_fw_rf_serial_write(hw, rfpath, regaddr, data);
+       }
+
+       spin_unlock_irqrestore(&rtlpriv->locks.rf_lock, flags);
+
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE,
+                "regaddr(%#x), bitmask(%#x), data(%#x), rfpath(%#x)\n",
+                regaddr, bitmask, data, rfpath);
+}
+
+static u32 _phy_fw_rf_serial_read(struct ieee80211_hw *hw,
+                                           enum radio_path rfpath, u32 offset)
+{
+       RT_ASSERT(false, "deprecated!\n");
+       return 0;
+}
+
+static void _phy_fw_rf_serial_write(struct ieee80211_hw *hw,
+                                   enum radio_path rfpath,
+                                   u32 offset, u32 data)
+{
+       RT_ASSERT(false, "deprecated!\n");
+}
+
+static u32 _phy_rf_serial_read(struct ieee80211_hw *hw,
+                              enum radio_path rfpath, u32 offset)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+       u32 newoffset;
+       u32 tmplong, tmplong2;
+       u8 rfpi_enable = 0;
+       u32 retvalue;
+
+       offset &= 0x3f;
+       newoffset = offset;
+       if (RT_CANNOT_IO(hw)) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "return all one\n");
+               return 0xFFFFFFFF;
+       }
+       tmplong = rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD);
+       if (rfpath == RF90_PATH_A)
+               tmplong2 = tmplong;
+       else
+               tmplong2 = rtl_get_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD);
+       tmplong2 = (tmplong2 & (~BLSSIREADADDRESS)) |
+           (newoffset << 23) | BLSSIREADEDGE;
+       rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+                     tmplong & (~BLSSIREADEDGE));
+       mdelay(1);
+       rtl_set_bbreg(hw, pphyreg->rfhssi_para2, MASKDWORD, tmplong2);
+       mdelay(1);
+       rtl_set_bbreg(hw, RFPGA0_XA_HSSIPARAMETER2, MASKDWORD,
+                     tmplong | BLSSIREADEDGE);
+       mdelay(1);
+       if (rfpath == RF90_PATH_A)
+               rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XA_HSSIPARAMETER1,
+                                                BIT(8));
+       else if (rfpath == RF90_PATH_B)
+               rfpi_enable = (u8) rtl_get_bbreg(hw, RFPGA0_XB_HSSIPARAMETER1,
+                                                BIT(8));
+       if (rfpi_enable)
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rbpi,
+                                        BLSSIREADBACKDATA);
+       else
+               retvalue = rtl_get_bbreg(hw, pphyreg->rf_rb,
+                                        BLSSIREADBACKDATA);
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFR-%d Addr[0x%x]=0x%x\n",
+                rfpath, pphyreg->rf_rb, retvalue);
+       return retvalue;
+}
+
+static void _phy_rf_serial_write(struct ieee80211_hw *hw,
+                                enum radio_path rfpath, u32 offset, u32 data)
+{
+       u32 data_and_addr;
+       u32 newoffset;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct bb_reg_def *pphyreg = &rtlphy->phyreg_def[rfpath];
+
+       if (RT_CANNOT_IO(hw)) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "stop\n");
+               return;
+       }
+       offset &= 0x3f;
+       newoffset = offset;
+       data_and_addr = ((newoffset << 20) | (data & 0x000fffff)) & 0x0fffffff;
+       rtl_set_bbreg(hw, pphyreg->rf3wire_offset, MASKDWORD, data_and_addr);
+       RT_TRACE(rtlpriv, COMP_RF, DBG_TRACE, "RFW-%d Addr[0x%x]=0x%x\n",
+                rfpath, pphyreg->rf3wire_offset, data_and_addr);
+}
+
+static u32 _phy_calculate_bit_shift(u32 bitmask)
+{
+       u32 i;
+
+       for (i = 0; i <= 31; i++) {
+               if (((bitmask >> i) & 0x1) == 1)
+                       break;
+       }
+       return i;
+}
+
+static void _rtl8723ae_phy_bb_config_1t(struct ieee80211_hw *hw)
+{
+       rtl_set_bbreg(hw, RFPGA0_TXINFO, 0x3, 0x2);
+       rtl_set_bbreg(hw, RFPGA1_TXINFO, 0x300033, 0x200022);
+       rtl_set_bbreg(hw, RCCK0_AFESETTING, MASKBYTE3, 0x45);
+       rtl_set_bbreg(hw, ROFDM0_TRXPATHENABLE, MASKBYTE0, 0x23);
+       rtl_set_bbreg(hw, ROFDM0_AGCPARAMETER1, 0x30, 0x1);
+       rtl_set_bbreg(hw, 0xe74, 0x0c000000, 0x2);
+       rtl_set_bbreg(hw, 0xe78, 0x0c000000, 0x2);
+       rtl_set_bbreg(hw, 0xe7c, 0x0c000000, 0x2);
+       rtl_set_bbreg(hw, 0xe80, 0x0c000000, 0x2);
+       rtl_set_bbreg(hw, 0xe88, 0x0c000000, 0x2);
+}
+
+bool rtl8723ae_phy_mac_config(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       bool rtstatus = _phy_cfg_mac_w_header(hw);
+       rtl_write_byte(rtlpriv, 0x04CA, 0x0A);
+       return rtstatus;
+}
+
+bool rtl8723ae_phy_bb_config(struct ieee80211_hw *hw)
+{
+       bool rtstatus = true;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmpu1b;
+       u8 reg_hwparafile = 1;
+
+       _phy_init_bb_rf_reg_def(hw);
+
+       /* 1. 0x28[1] = 1 */
+       tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_PLL_CTRL);
+       udelay(2);
+       rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL, (tmpu1b|BIT(1)));
+       udelay(2);
+       /* 2. 0x29[7:0] = 0xFF */
+       rtl_write_byte(rtlpriv, REG_AFE_PLL_CTRL+1, 0xff);
+       udelay(2);
+
+       /* 3. 0x02[1:0] = 2b'11 */
+       tmpu1b = rtl_read_byte(rtlpriv, REG_SYS_FUNC_EN);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, (tmpu1b |
+                      FEN_BB_GLB_RSTn | FEN_BBRSTB));
+
+       /* 4. 0x25[6] = 0 */
+       tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+1);
+       rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+1, (tmpu1b&(~BIT(6))));
+
+       /* 5. 0x24[20] = 0      Advised by SD3 Alex Wang. 2011.02.09. */
+       tmpu1b = rtl_read_byte(rtlpriv, REG_AFE_XTAL_CTRL+2);
+       rtl_write_byte(rtlpriv, REG_AFE_XTAL_CTRL+2, (tmpu1b&(~BIT(4))));
+
+       /* 6. 0x1f[7:0] = 0x07 */
+       rtl_write_byte(rtlpriv, REG_RF_CTRL, 0x07);
+
+       if (reg_hwparafile == 1)
+               rtstatus = _phy_bb8192c_config_parafile(hw);
+       return rtstatus;
+}
+
+bool rtl8723ae_phy_rf_config(struct ieee80211_hw *hw)
+{
+       return rtl8723ae_phy_rf6052_config(hw);
+}
+
+static bool _phy_bb8192c_config_parafile(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       bool rtstatus;
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "==>\n");
+       rtstatus = _phy_cfg_bb_w_header(hw, BASEBAND_CONFIG_PHY_REG);
+       if (rtstatus != true) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Write BB Reg Fail!!");
+               return false;
+       }
+
+       if (rtlphy->rf_type == RF_1T2R) {
+               _rtl8723ae_phy_bb_config_1t(hw);
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Config to 1T!!\n");
+       }
+       if (rtlefuse->autoload_failflag == false) {
+               rtlphy->pwrgroup_cnt = 0;
+               rtstatus = _phy_cfg_bb_w_pgheader(hw, BASEBAND_CONFIG_PHY_REG);
+       }
+       if (rtstatus != true) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "BB_PG Reg Fail!!");
+               return false;
+       }
+       rtstatus = _phy_cfg_bb_w_header(hw, BASEBAND_CONFIG_AGC_TAB);
+       if (rtstatus != true) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "AGC Table Fail\n");
+               return false;
+       }
+       rtlphy->cck_high_power = (bool) (rtl_get_bbreg(hw,
+                                        RFPGA0_XA_HSSIPARAMETER2, 0x200));
+       return true;
+}
+
+static bool _phy_cfg_mac_w_header(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 i;
+       u32 arraylength;
+       u32 *ptrarray;
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Read Rtl723MACPHY_Array\n");
+       arraylength = RTL8723E_MACARRAYLENGTH;
+       ptrarray = RTL8723EMAC_ARRAY;
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                "Img:RTL8192CEMAC_2T_ARRAY\n");
+       for (i = 0; i < arraylength; i = i + 2)
+               rtl_write_byte(rtlpriv, ptrarray[i], (u8) ptrarray[i + 1]);
+       return true;
+}
+
+static bool _phy_cfg_bb_w_header(struct ieee80211_hw *hw, u8 configtype)
+{
+       int i;
+       u32 *phy_regarray_table;
+       u32 *agctab_array_table;
+       u16 phy_reg_arraylen, agctab_arraylen;
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       agctab_arraylen = RTL8723E_AGCTAB_1TARRAYLENGTH;
+       agctab_array_table = RTL8723EAGCTAB_1TARRAY;
+       phy_reg_arraylen = RTL8723E_PHY_REG_1TARRAY_LENGTH;
+       phy_regarray_table = RTL8723EPHY_REG_1TARRAY;
+       if (configtype == BASEBAND_CONFIG_PHY_REG) {
+               for (i = 0; i < phy_reg_arraylen; i = i + 2) {
+                       if (phy_regarray_table[i] == 0xfe)
+                               mdelay(50);
+                       else if (phy_regarray_table[i] == 0xfd)
+                               mdelay(5);
+                       else if (phy_regarray_table[i] == 0xfc)
+                               mdelay(1);
+                       else if (phy_regarray_table[i] == 0xfb)
+                               udelay(50);
+                       else if (phy_regarray_table[i] == 0xfa)
+                               udelay(5);
+                       else if (phy_regarray_table[i] == 0xf9)
+                               udelay(1);
+                       rtl_set_bbreg(hw, phy_regarray_table[i], MASKDWORD,
+                                     phy_regarray_table[i + 1]);
+                       udelay(1);
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                "The phy_regarray_table[0] is %x"
+                                " Rtl819XPHY_REGArray[1] is %x\n",
+                                phy_regarray_table[i],
+                                phy_regarray_table[i + 1]);
+               }
+       } else if (configtype == BASEBAND_CONFIG_AGC_TAB) {
+               for (i = 0; i < agctab_arraylen; i = i + 2) {
+                       rtl_set_bbreg(hw, agctab_array_table[i], MASKDWORD,
+                                     agctab_array_table[i + 1]);
+                       udelay(1);
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                "The agctab_array_table[0] is "
+                                "%x Rtl819XPHY_REGArray[1] is %x\n",
+                                agctab_array_table[i],
+                                agctab_array_table[i + 1]);
+               }
+       }
+       return true;
+}
+
+static void _st_pwrIdx_dfrate_off(struct ieee80211_hw *hw, u32 regaddr,
+                                 u32 bitmask, u32 data)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       switch (regaddr) {
+       case RTXAGC_A_RATE18_06:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][0] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][0]);
+               break;
+       case RTXAGC_A_RATE54_24:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][1] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][1]);
+               break;
+       case RTXAGC_A_CCK1_MCS32:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][6] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][6]);
+               break;
+       case RTXAGC_B_CCK11_A_CCK2_11:
+               if (bitmask == 0xffffff00) {
+                       rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7] = data;
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                "MCSTxPowerLevelOriginalOffset[%d][7] = 0x%x\n",
+                                rtlphy->pwrgroup_cnt,
+                                rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][7]);
+               }
+               if (bitmask == 0x000000ff) {
+                       rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15] = data;
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                "MCSTxPowerLevelOriginalOffset[%d][15] = 0x%x\n",
+                                rtlphy->pwrgroup_cnt,
+                                rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][15]);
+               }
+               break;
+       case RTXAGC_A_MCS03_MCS00:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][2] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][2]);
+               break;
+       case RTXAGC_A_MCS07_MCS04:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][3] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][3]);
+               break;
+       case RTXAGC_A_MCS11_MCS08:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][4] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][4]);
+               break;
+       case RTXAGC_A_MCS15_MCS12:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][5] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][5]);
+               break;
+       case RTXAGC_B_RATE18_06:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][8] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][8]);
+               break;
+       case RTXAGC_B_RATE54_24:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][9] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][9]);
+               break;
+       case RTXAGC_B_CCK1_55_MCS32:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][14] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][14]);
+               break;
+       case RTXAGC_B_MCS03_MCS00:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][10] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][10]);
+               break;
+       case RTXAGC_B_MCS07_MCS04:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][11] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][11]);
+               break;
+       case RTXAGC_B_MCS11_MCS08:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][12] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][12]);
+               break;
+       case RTXAGC_B_MCS15_MCS12:
+               rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13] = data;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                        "MCSTxPowerLevelOriginalOffset[%d][13] = 0x%x\n",
+                        rtlphy->pwrgroup_cnt,
+                        rtlphy->mcs_offset[rtlphy->pwrgroup_cnt][13]);
+               rtlphy->pwrgroup_cnt++;
+               break;
+       }
+}
+
+static bool _phy_cfg_bb_w_pgheader(struct ieee80211_hw *hw, u8 configtype)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i;
+       u32 *phy_regarray_table_pg;
+       u16 phy_regarray_pg_len;
+
+       phy_regarray_pg_len = RTL8723E_PHY_REG_ARRAY_PGLENGTH;
+       phy_regarray_table_pg = RTL8723EPHY_REG_ARRAY_PG;
+
+       if (configtype == BASEBAND_CONFIG_PHY_REG) {
+               for (i = 0; i < phy_regarray_pg_len; i = i + 3) {
+                       if (phy_regarray_table_pg[i] == 0xfe)
+                               mdelay(50);
+                       else if (phy_regarray_table_pg[i] == 0xfd)
+                               mdelay(5);
+                       else if (phy_regarray_table_pg[i] == 0xfc)
+                               mdelay(1);
+                       else if (phy_regarray_table_pg[i] == 0xfb)
+                               udelay(50);
+                       else if (phy_regarray_table_pg[i] == 0xfa)
+                               udelay(5);
+                       else if (phy_regarray_table_pg[i] == 0xf9)
+                               udelay(1);
+
+                       _st_pwrIdx_dfrate_off(hw, phy_regarray_table_pg[i],
+                                             phy_regarray_table_pg[i + 1],
+                                             phy_regarray_table_pg[i + 2]);
+               }
+       } else {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                        "configtype != BaseBand_Config_PHY_REG\n");
+       }
+       return true;
+}
+
+bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+                                            enum radio_path rfpath)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int i;
+       bool rtstatus = true;
+       u32 *radioa_array_table;
+       u32 *radiob_array_table;
+       u16 radioa_arraylen, radiob_arraylen;
+
+       radioa_arraylen = Rtl8723ERADIOA_1TARRAYLENGTH;
+       radioa_array_table = RTL8723E_RADIOA_1TARRAY;
+       radiob_arraylen = RTL8723E_RADIOB_1TARRAYLENGTH;
+       radiob_array_table = RTL8723E_RADIOB_1TARRAY;
+
+       rtstatus = true;
+
+       switch (rfpath) {
+       case RF90_PATH_A:
+               for (i = 0; i < radioa_arraylen; i = i + 2) {
+                       if (radioa_array_table[i] == 0xfe)
+                               mdelay(50);
+                       else if (radioa_array_table[i] == 0xfd)
+                               mdelay(5);
+                       else if (radioa_array_table[i] == 0xfc)
+                               mdelay(1);
+                       else if (radioa_array_table[i] == 0xfb)
+                               udelay(50);
+                       else if (radioa_array_table[i] == 0xfa)
+                               udelay(5);
+                       else if (radioa_array_table[i] == 0xf9)
+                               udelay(1);
+                       else {
+                               rtl_set_rfreg(hw, rfpath, radioa_array_table[i],
+                                             RFREG_OFFSET_MASK,
+                                             radioa_array_table[i + 1]);
+                               udelay(1);
+                       }
+               }
+               break;
+       case RF90_PATH_B:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       case RF90_PATH_C:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       case RF90_PATH_D:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       }
+       return true;
+}
+
+void rtl8723ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       rtlphy->default_initialgain[0] =
+           (u8) rtl_get_bbreg(hw, ROFDM0_XAAGCCORE1, MASKBYTE0);
+       rtlphy->default_initialgain[1] =
+           (u8) rtl_get_bbreg(hw, ROFDM0_XBAGCCORE1, MASKBYTE0);
+       rtlphy->default_initialgain[2] =
+           (u8) rtl_get_bbreg(hw, ROFDM0_XCAGCCORE1, MASKBYTE0);
+       rtlphy->default_initialgain[3] =
+           (u8) rtl_get_bbreg(hw, ROFDM0_XDAGCCORE1, MASKBYTE0);
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                "Default initial gain (c50=0x%x, c58=0x%x, c60=0x%x, c68=0x%x\n",
+                 rtlphy->default_initialgain[0],
+                 rtlphy->default_initialgain[1],
+                 rtlphy->default_initialgain[2],
+                 rtlphy->default_initialgain[3]);
+
+       rtlphy->framesync = (u8) rtl_get_bbreg(hw,
+                                              ROFDM0_RXDETECTOR3, MASKBYTE0);
+       rtlphy->framesync_c34 = rtl_get_bbreg(hw,
+                                             ROFDM0_RXDETECTOR2, MASKDWORD);
+
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                "Default framesync (0x%x) = 0x%x\n",
+                ROFDM0_RXDETECTOR3, rtlphy->framesync);
+}
+
+static void _phy_init_bb_rf_reg_def(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+       rtlphy->phyreg_def[RF90_PATH_B].rfintfs = RFPGA0_XAB_RFINTERFACESW;
+       rtlphy->phyreg_def[RF90_PATH_C].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+       rtlphy->phyreg_def[RF90_PATH_D].rfintfs = RFPGA0_XCD_RFINTERFACESW;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+       rtlphy->phyreg_def[RF90_PATH_B].rfintfi = RFPGA0_XAB_RFINTERFACERB;
+       rtlphy->phyreg_def[RF90_PATH_C].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+       rtlphy->phyreg_def[RF90_PATH_D].rfintfi = RFPGA0_XCD_RFINTERFACERB;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfintfo = RFPGA0_XA_RFINTERFACEOE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfintfo = RFPGA0_XB_RFINTERFACEOE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfintfe = RFPGA0_XA_RFINTERFACEOE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfintfe = RFPGA0_XB_RFINTERFACEOE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rf3wire_offset =
+                           RFPGA0_XA_LSSIPARAMETER;
+       rtlphy->phyreg_def[RF90_PATH_B].rf3wire_offset =
+                           RFPGA0_XB_LSSIPARAMETER;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+       rtlphy->phyreg_def[RF90_PATH_B].rflssi_select = rFPGA0_XAB_RFPARAMETER;
+       rtlphy->phyreg_def[RF90_PATH_C].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+       rtlphy->phyreg_def[RF90_PATH_D].rflssi_select = rFPGA0_XCD_RFPARAMETER;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+       rtlphy->phyreg_def[RF90_PATH_B].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+       rtlphy->phyreg_def[RF90_PATH_C].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+       rtlphy->phyreg_def[RF90_PATH_D].rftxgain_stage = RFPGA0_TXGAINSTAGE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para1 = RFPGA0_XA_HSSIPARAMETER1;
+       rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para1 = RFPGA0_XB_HSSIPARAMETER1;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfhssi_para2 = RFPGA0_XA_HSSIPARAMETER2;
+       rtlphy->phyreg_def[RF90_PATH_B].rfhssi_para2 = RFPGA0_XB_HSSIPARAMETER2;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_B].rfsw_ctrl = RFPGA0_XAB_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_C].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+       rtlphy->phyreg_def[RF90_PATH_D].rfsw_ctrl = RFPGA0_XCD_SWITCHCONTROL;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfagc_control1 = ROFDM0_XAAGCCORE1;
+       rtlphy->phyreg_def[RF90_PATH_B].rfagc_control1 = ROFDM0_XBAGCCORE1;
+       rtlphy->phyreg_def[RF90_PATH_C].rfagc_control1 = ROFDM0_XCAGCCORE1;
+       rtlphy->phyreg_def[RF90_PATH_D].rfagc_control1 = ROFDM0_XDAGCCORE1;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfagc_control2 = ROFDM0_XAAGCCORE2;
+       rtlphy->phyreg_def[RF90_PATH_B].rfagc_control2 = ROFDM0_XBAGCCORE2;
+       rtlphy->phyreg_def[RF90_PATH_C].rfagc_control2 = ROFDM0_XCAGCCORE2;
+       rtlphy->phyreg_def[RF90_PATH_D].rfagc_control2 = ROFDM0_XDAGCCORE2;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfrxiq_imbal = ROFDM0_XARXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfrxiq_imbal = ROFDM0_XBRXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rfrxiq_imbal = ROFDM0_XCRXIQIMBANLANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rfrxiq_imbal = ROFDM0_XDRXIQIMBALANCE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rfrx_afe = ROFDM0_XARXAFE;
+       rtlphy->phyreg_def[RF90_PATH_B].rfrx_afe = ROFDM0_XBRXAFE;
+       rtlphy->phyreg_def[RF90_PATH_C].rfrx_afe = ROFDM0_XCRXAFE;
+       rtlphy->phyreg_def[RF90_PATH_D].rfrx_afe = ROFDM0_XDRXAFE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rftxiq_imbal = ROFDM0_XATXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_B].rftxiq_imbal = ROFDM0_XBTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_C].rftxiq_imbal = ROFDM0_XCTXIQIMBALANCE;
+       rtlphy->phyreg_def[RF90_PATH_D].rftxiq_imbal = ROFDM0_XDTXIQIMBALANCE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rftx_afe = ROFDM0_XATXAFE;
+       rtlphy->phyreg_def[RF90_PATH_B].rftx_afe = ROFDM0_XBTXAFE;
+       rtlphy->phyreg_def[RF90_PATH_C].rftx_afe = ROFDM0_XCTXAFE;
+       rtlphy->phyreg_def[RF90_PATH_D].rftx_afe = ROFDM0_XDTXAFE;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rb = RFPGA0_XA_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rb = RFPGA0_XB_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_C].rf_rb = RFPGA0_XC_LSSIREADBACK;
+       rtlphy->phyreg_def[RF90_PATH_D].rf_rb = RFPGA0_XD_LSSIREADBACK;
+
+       rtlphy->phyreg_def[RF90_PATH_A].rf_rbpi = TRANSCEIVEA_HSPI_READBACK;
+       rtlphy->phyreg_def[RF90_PATH_B].rf_rbpi = TRANSCEIVEB_HSPI_READBACK;
+}
+
+void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw, long *powerlevel)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 txpwr_level;
+       long txpwr_dbm;
+
+       txpwr_level = rtlphy->cur_cck_txpwridx;
+       txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_B, txpwr_level);
+       txpwr_level = rtlphy->cur_ofdm24g_txpwridx +
+           rtlefuse->legacy_ht_txpowerdiff;
+       if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G, txpwr_level) > txpwr_dbm)
+               txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_G,
+                                                 txpwr_level);
+       txpwr_level = rtlphy->cur_ofdm24g_txpwridx;
+       if (_phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G, txpwr_level) >
+           txpwr_dbm)
+               txpwr_dbm = _phy_txpwr_idx_to_dbm(hw, WIRELESS_MODE_N_24G,
+                                                 txpwr_level);
+       *powerlevel = txpwr_dbm;
+}
+
+static void _rtl8723ae_get_txpower_index(struct ieee80211_hw *hw, u8 channel,
+                                        u8 *cckpowerlevel, u8 *ofdmpowerlevel)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 index = (channel - 1);
+
+       cckpowerlevel[RF90_PATH_A] =
+           rtlefuse->txpwrlevel_cck[RF90_PATH_A][index];
+       cckpowerlevel[RF90_PATH_B] =
+           rtlefuse->txpwrlevel_cck[RF90_PATH_B][index];
+       if (get_rf_type(rtlphy) == RF_1T2R || get_rf_type(rtlphy) == RF_1T1R) {
+               ofdmpowerlevel[RF90_PATH_A] =
+                   rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_A][index];
+               ofdmpowerlevel[RF90_PATH_B] =
+                   rtlefuse->txpwrlevel_ht40_1s[RF90_PATH_B][index];
+       } else if (get_rf_type(rtlphy) == RF_2T2R) {
+               ofdmpowerlevel[RF90_PATH_A] =
+                   rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_A][index];
+               ofdmpowerlevel[RF90_PATH_B] =
+                   rtlefuse->txpwrlevel_ht40_2s[RF90_PATH_B][index];
+       }
+}
+
+static void _rtl8723ae_ccxpower_index_check(struct ieee80211_hw *hw,
+                                           u8 channel, u8 *cckpowerlevel,
+                                           u8 *ofdmpowerlevel)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       rtlphy->cur_cck_txpwridx = cckpowerlevel[0];
+       rtlphy->cur_ofdm24g_txpwridx = ofdmpowerlevel[0];
+}
+
+void rtl8723ae_phy_set_txpower_level(struct ieee80211_hw *hw, u8 channel)
+{
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 cckpowerlevel[2], ofdmpowerlevel[2];
+
+       if (rtlefuse->txpwr_fromeprom == false)
+               return;
+       _rtl8723ae_get_txpower_index(hw, channel, &cckpowerlevel[0],
+                                    &ofdmpowerlevel[0]);
+       _rtl8723ae_ccxpower_index_check(hw, channel, &cckpowerlevel[0],
+                                       &ofdmpowerlevel[0]);
+       rtl8723ae_phy_rf6052_set_cck_txpower(hw, &cckpowerlevel[0]);
+       rtl8723ae_phy_rf6052_set_ofdm_txpower(hw, &ofdmpowerlevel[0], channel);
+}
+
+bool rtl8723ae_phy_update_txpower_dbm(struct ieee80211_hw *hw, long power_indbm)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 idx;
+       u8 rf_path;
+       u8 ccktxpwridx = _phy_dbm_to_txpwr_Idx(hw, WIRELESS_MODE_B,
+                                              power_indbm);
+       u8 ofdmtxpwridx = _phy_dbm_to_txpwr_Idx(hw, WIRELESS_MODE_N_24G,
+                                               power_indbm);
+       if (ofdmtxpwridx - rtlefuse->legacy_ht_txpowerdiff > 0)
+               ofdmtxpwridx -= rtlefuse->legacy_ht_txpowerdiff;
+       else
+               ofdmtxpwridx = 0;
+       RT_TRACE(rtlpriv, COMP_TXAGC, DBG_TRACE,
+                "%lx dBm, ccktxpwridx = %d, ofdmtxpwridx = %d\n",
+                power_indbm, ccktxpwridx, ofdmtxpwridx);
+       for (idx = 0; idx < 14; idx++) {
+               for (rf_path = 0; rf_path < 2; rf_path++) {
+                       rtlefuse->txpwrlevel_cck[rf_path][idx] = ccktxpwridx;
+                       rtlefuse->txpwrlevel_ht40_1s[rf_path][idx] =
+                                                           ofdmtxpwridx;
+                       rtlefuse->txpwrlevel_ht40_2s[rf_path][idx] =
+                                                           ofdmtxpwridx;
+               }
+       }
+       rtl8723ae_phy_set_txpower_level(hw, rtlphy->current_channel);
+       return true;
+}
+
+static u8 _phy_dbm_to_txpwr_Idx(struct ieee80211_hw *hw,
+                               enum wireless_mode wirelessmode,
+                               long power_indbm)
+{
+       u8 txpwridx;
+       long offset;
+
+       switch (wirelessmode) {
+       case WIRELESS_MODE_B:
+               offset = -7;
+               break;
+       case WIRELESS_MODE_G:
+       case WIRELESS_MODE_N_24G:
+               offset = -8;
+               break;
+       default:
+               offset = -8;
+               break;
+       }
+
+       if ((power_indbm - offset) > 0)
+               txpwridx = (u8) ((power_indbm - offset) * 2);
+       else
+               txpwridx = 0;
+
+       if (txpwridx > MAX_TXPWR_IDX_NMODE_92S)
+               txpwridx = MAX_TXPWR_IDX_NMODE_92S;
+
+       return txpwridx;
+}
+
+static long _phy_txpwr_idx_to_dbm(struct ieee80211_hw *hw,
+                                 enum wireless_mode wirelessmode, u8 txpwridx)
+{
+       long offset;
+       long pwrout_dbm;
+
+       switch (wirelessmode) {
+       case WIRELESS_MODE_B:
+               offset = -7;
+               break;
+       case WIRELESS_MODE_G:
+       case WIRELESS_MODE_N_24G:
+               offset = -8;
+               break;
+       default:
+               offset = -8;
+               break;
+       }
+       pwrout_dbm = txpwridx / 2 + offset;
+       return pwrout_dbm;
+}
+
+void rtl8723ae_phy_scan_operation_backup(struct ieee80211_hw *hw, u8 operation)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       enum io_type iotype;
+
+       if (!is_hal_stop(rtlhal)) {
+               switch (operation) {
+               case SCAN_OPT_BACKUP:
+                       iotype = IO_CMD_PAUSE_DM_BY_SCAN;
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                     HW_VAR_IO_CMD,
+                                                     (u8 *)&iotype);
+
+                       break;
+               case SCAN_OPT_RESTORE:
+                       iotype = IO_CMD_RESUME_DM_BY_SCAN;
+                       rtlpriv->cfg->ops->set_hw_reg(hw,
+                                                     HW_VAR_IO_CMD,
+                                                     (u8 *)&iotype);
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "Unknown Scan Backup operation.\n");
+                       break;
+               }
+       }
+}
+
+void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       u8 reg_bw_opmode;
+       u8 reg_prsr_rsc;
+
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+                "Switch to %s bandwidth\n",
+                rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20 ?
+                "20MHz" : "40MHz");
+
+       if (is_hal_stop(rtlhal)) {
+               rtlphy->set_bwmode_inprogress = false;
+               return;
+       }
+
+       reg_bw_opmode = rtl_read_byte(rtlpriv, REG_BWOPMODE);
+       reg_prsr_rsc = rtl_read_byte(rtlpriv, REG_RRSR + 2);
+
+       switch (rtlphy->current_chan_bw) {
+       case HT_CHANNEL_WIDTH_20:
+               reg_bw_opmode |= BW_OPMODE_20MHZ;
+               rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               reg_bw_opmode &= ~BW_OPMODE_20MHZ;
+               rtl_write_byte(rtlpriv, REG_BWOPMODE, reg_bw_opmode);
+               reg_prsr_rsc =
+                   (reg_prsr_rsc & 0x90) | (mac->cur_40_prime_sc << 5);
+               rtl_write_byte(rtlpriv, REG_RRSR + 2, reg_prsr_rsc);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+               break;
+       }
+
+       switch (rtlphy->current_chan_bw) {
+       case HT_CHANNEL_WIDTH_20:
+               rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x0);
+               rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x0);
+               rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 1);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               rtl_set_bbreg(hw, RFPGA0_RFMOD, BRFMOD, 0x1);
+               rtl_set_bbreg(hw, RFPGA1_RFMOD, BRFMOD, 0x1);
+
+               rtl_set_bbreg(hw, RCCK0_SYSTEM, BCCK_SIDEBAND,
+                             (mac->cur_40_prime_sc >> 1));
+               rtl_set_bbreg(hw, ROFDM1_LSTF, 0xC00, mac->cur_40_prime_sc);
+               rtl_set_bbreg(hw, RFPGA0_ANALOGPARAMETER2, BIT(10), 0);
+
+               rtl_set_bbreg(hw, 0x818, (BIT(26) | BIT(27)),
+                             (mac->cur_40_prime_sc ==
+                              HAL_PRIME_CHNL_OFFSET_LOWER) ? 2 : 1);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "unknown bandwidth: %#X\n", rtlphy->current_chan_bw);
+               break;
+       }
+       rtl8723ae_phy_rf6052_set_bandwidth(hw, rtlphy->current_chan_bw);
+       rtlphy->set_bwmode_inprogress = false;
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n");
+}
+
+void rtl8723ae_phy_set_bw_mode(struct ieee80211_hw *hw,
+                              enum nl80211_channel_type ch_type)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u8 tmp_bw = rtlphy->current_chan_bw;
+
+       if (rtlphy->set_bwmode_inprogress)
+               return;
+       rtlphy->set_bwmode_inprogress = true;
+       if ((!is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+               rtl8723ae_phy_set_bw_mode_callback(hw);
+       } else {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                        "FALSE driver sleep or unload\n");
+               rtlphy->set_bwmode_inprogress = false;
+               rtlphy->current_chan_bw = tmp_bw;
+       }
+}
+
+void rtl8723ae_phy_sw_chnl_callback(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u32 delay;
+
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE,
+                "switch to channel%d\n", rtlphy->current_channel);
+       if (is_hal_stop(rtlhal))
+               return;
+       do {
+               if (!rtlphy->sw_chnl_inprogress)
+                       break;
+               if (!_phy_sw_chnl_step_by_step
+                   (hw, rtlphy->current_channel, &rtlphy->sw_chnl_stage,
+                    &rtlphy->sw_chnl_step, &delay)) {
+                       if (delay > 0)
+                               mdelay(delay);
+                       else
+                               continue;
+               } else {
+                       rtlphy->sw_chnl_inprogress = false;
+               }
+               break;
+       } while (true);
+       RT_TRACE(rtlpriv, COMP_SCAN, DBG_TRACE, "<==\n");
+}
+
+u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       if (rtlphy->sw_chnl_inprogress)
+               return 0;
+       if (rtlphy->set_bwmode_inprogress)
+               return 0;
+       RT_ASSERT((rtlphy->current_channel <= 14),
+                 "WIRELESS_MODE_G but channel>14");
+       rtlphy->sw_chnl_inprogress = true;
+       rtlphy->sw_chnl_stage = 0;
+       rtlphy->sw_chnl_step = 0;
+       if (!(is_hal_stop(rtlhal)) && !(RT_CANNOT_IO(hw))) {
+               rtl8723ae_phy_sw_chnl_callback(hw);
+               RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+                        "sw_chnl_inprogress false schdule workitem\n");
+               rtlphy->sw_chnl_inprogress = false;
+       } else {
+               RT_TRACE(rtlpriv, COMP_CHAN, DBG_LOUD,
+                        "sw_chnl_inprogress false driver sleep or unload\n");
+               rtlphy->sw_chnl_inprogress = false;
+       }
+       return 1;
+}
+
+static void _rtl8723ae_phy_sw_rf_seting(struct ieee80211_hw *hw, u8 channel)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version)) {
+               if (channel == 6 && rtlphy->current_chan_bw ==
+                   HT_CHANNEL_WIDTH_20)
+                       rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD,
+                                     0x00255);
+               else{
+                       u32 backupRF0x1A = (u32)rtl_get_rfreg(hw, RF90_PATH_A,
+                                          RF_RX_G1, RFREG_OFFSET_MASK);
+                       rtl_set_rfreg(hw, RF90_PATH_A, RF_RX_G1, MASKDWORD,
+                                     backupRF0x1A);
+               }
+       }
+}
+
+static bool _phy_sw_chnl_step_by_step(struct ieee80211_hw *hw, u8 channel,
+                                     u8 *stage, u8 *step, u32 *delay)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct swchnlcmd precommoncmd[MAX_PRECMD_CNT];
+       u32 precommoncmdcnt;
+       struct swchnlcmd postcommoncmd[MAX_POSTCMD_CNT];
+       u32 postcommoncmdcnt;
+       struct swchnlcmd rfdependcmd[MAX_RFDEPENDCMD_CNT];
+       u32 rfdependcmdcnt;
+       struct swchnlcmd *currentcmd = NULL;
+       u8 rfpath;
+       u8 num_total_rfpath = rtlphy->num_total_rfpath;
+
+       precommoncmdcnt = 0;
+       _phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+                                 MAX_PRECMD_CNT, CMDID_SET_TXPOWEROWER_LEVEL,
+                                 0, 0, 0);
+       _phy_set_sw_chnl_cmdarray(precommoncmd, precommoncmdcnt++,
+                                 MAX_PRECMD_CNT, CMDID_END, 0, 0, 0);
+       postcommoncmdcnt = 0;
+
+       _phy_set_sw_chnl_cmdarray(postcommoncmd, postcommoncmdcnt++,
+                                 MAX_POSTCMD_CNT, CMDID_END, 0, 0, 0);
+       rfdependcmdcnt = 0;
+
+       RT_ASSERT((channel >= 1 && channel <= 14),
+                 "illegal channel for Zebra: %d\n", channel);
+
+       _phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+                                 MAX_RFDEPENDCMD_CNT, CMDID_RF_WRITEREG,
+                                 RF_CHNLBW, channel, 10);
+
+       _phy_set_sw_chnl_cmdarray(rfdependcmd, rfdependcmdcnt++,
+                                 MAX_RFDEPENDCMD_CNT, CMDID_END, 0, 0, 0);
+
+       do {
+               switch (*stage) {
+               case 0:
+                       currentcmd = &precommoncmd[*step];
+                       break;
+               case 1:
+                       currentcmd = &rfdependcmd[*step];
+                       break;
+               case 2:
+                       currentcmd = &postcommoncmd[*step];
+                       break;
+               }
+
+               if (currentcmd->cmdid == CMDID_END) {
+                       if ((*stage) == 2) {
+                               return true;
+                       } else {
+                               (*stage)++;
+                               (*step) = 0;
+                               continue;
+                       }
+               }
+
+               switch (currentcmd->cmdid) {
+               case CMDID_SET_TXPOWEROWER_LEVEL:
+                       rtl8723ae_phy_set_txpower_level(hw, channel);
+                       break;
+               case CMDID_WRITEPORT_ULONG:
+                       rtl_write_dword(rtlpriv, currentcmd->para1,
+                                       currentcmd->para2);
+                       break;
+               case CMDID_WRITEPORT_USHORT:
+                       rtl_write_word(rtlpriv, currentcmd->para1,
+                                      (u16) currentcmd->para2);
+                       break;
+               case CMDID_WRITEPORT_UCHAR:
+                       rtl_write_byte(rtlpriv, currentcmd->para1,
+                                      (u8) currentcmd->para2);
+                       break;
+               case CMDID_RF_WRITEREG:
+                       for (rfpath = 0; rfpath < num_total_rfpath; rfpath++) {
+                               rtlphy->rfreg_chnlval[rfpath] =
+                                   ((rtlphy->rfreg_chnlval[rfpath] &
+                                     0xfffffc00) | currentcmd->para2);
+
+                               rtl_set_rfreg(hw, (enum radio_path)rfpath,
+                                             currentcmd->para1,
+                                             RFREG_OFFSET_MASK,
+                                             rtlphy->rfreg_chnlval[rfpath]);
+                       }
+                       _rtl8723ae_phy_sw_rf_seting(hw, channel);
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not process\n");
+                       break;
+               }
+
+               break;
+       } while (true);
+
+       (*delay) = currentcmd->msdelay;
+       (*step)++;
+       return false;
+}
+
+static bool _phy_set_sw_chnl_cmdarray(struct swchnlcmd *cmdtable,
+                                     u32 cmdtableidx, u32 cmdtablesz,
+                                     enum swchnlcmd_id cmdid, u32 para1,
+                                     u32 para2, u32 msdelay)
+{
+       struct swchnlcmd *pcmd;
+
+       if (cmdtable == NULL) {
+               RT_ASSERT(false, "cmdtable cannot be NULL.\n");
+               return false;
+       }
+
+       if (cmdtableidx >= cmdtablesz)
+               return false;
+
+       pcmd = cmdtable + cmdtableidx;
+       pcmd->cmdid = cmdid;
+       pcmd->para1 = para1;
+       pcmd->para2 = para2;
+       pcmd->msdelay = msdelay;
+       return true;
+}
+
+static u8 _rtl8723ae_phy_path_a_iqk(struct ieee80211_hw *hw, bool config_pathb)
+{
+       u32 reg_eac, reg_e94, reg_e9c, reg_ea4;
+       u8 result = 0x00;
+
+       rtl_set_bbreg(hw, 0xe30, MASKDWORD, 0x10008c1f);
+       rtl_set_bbreg(hw, 0xe34, MASKDWORD, 0x10008c1f);
+       rtl_set_bbreg(hw, 0xe38, MASKDWORD, 0x82140102);
+       rtl_set_bbreg(hw, 0xe3c, MASKDWORD,
+                     config_pathb ? 0x28160202 : 0x28160502);
+
+       if (config_pathb) {
+               rtl_set_bbreg(hw, 0xe50, MASKDWORD, 0x10008c22);
+               rtl_set_bbreg(hw, 0xe54, MASKDWORD, 0x10008c22);
+               rtl_set_bbreg(hw, 0xe58, MASKDWORD, 0x82140102);
+               rtl_set_bbreg(hw, 0xe5c, MASKDWORD, 0x28160202);
+       }
+
+       rtl_set_bbreg(hw, 0xe4c, MASKDWORD, 0x001028d1);
+       rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf9000000);
+       rtl_set_bbreg(hw, 0xe48, MASKDWORD, 0xf8000000);
+
+       mdelay(IQK_DELAY_TIME);
+
+       reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+       reg_e94 = rtl_get_bbreg(hw, 0xe94, MASKDWORD);
+       reg_e9c = rtl_get_bbreg(hw, 0xe9c, MASKDWORD);
+       reg_ea4 = rtl_get_bbreg(hw, 0xea4, MASKDWORD);
+
+       if (!(reg_eac & BIT(28)) &&
+           (((reg_e94 & 0x03FF0000) >> 16) != 0x142) &&
+           (((reg_e9c & 0x03FF0000) >> 16) != 0x42))
+               result |= 0x01;
+       else
+               return result;
+
+       if (!(reg_eac & BIT(27)) &&
+           (((reg_ea4 & 0x03FF0000) >> 16) != 0x132) &&
+           (((reg_eac & 0x03FF0000) >> 16) != 0x36))
+               result |= 0x02;
+       return result;
+}
+
+static u8 _rtl8723ae_phy_path_b_iqk(struct ieee80211_hw *hw)
+{
+       u32 reg_eac, reg_eb4, reg_ebc, reg_ec4, reg_ecc;
+       u8 result = 0x00;
+
+       rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000002);
+       rtl_set_bbreg(hw, 0xe60, MASKDWORD, 0x00000000);
+       mdelay(IQK_DELAY_TIME);
+       reg_eac = rtl_get_bbreg(hw, 0xeac, MASKDWORD);
+       reg_eb4 = rtl_get_bbreg(hw, 0xeb4, MASKDWORD);
+       reg_ebc = rtl_get_bbreg(hw, 0xebc, MASKDWORD);
+       reg_ec4 = rtl_get_bbreg(hw, 0xec4, MASKDWORD);
+       reg_ecc = rtl_get_bbreg(hw, 0xecc, MASKDWORD);
+
+       if (!(reg_eac & BIT(31)) &&
+           (((reg_eb4 & 0x03FF0000) >> 16) != 0x142) &&
+           (((reg_ebc & 0x03FF0000) >> 16) != 0x42))
+               result |= 0x01;
+       else
+               return result;
+       if (!(reg_eac & BIT(30)) &&
+           (((reg_ec4 & 0x03FF0000) >> 16) != 0x132) &&
+           (((reg_ecc & 0x03FF0000) >> 16) != 0x36))
+               result |= 0x02;
+       return result;
+}
+
+static void phy_path_a_fill_iqk_matrix(struct ieee80211_hw *hw, bool iqk_ok,
+                                      long result[][8], u8 final_candidate,
+                                      bool btxonly)
+{
+       u32 oldval_0, x, tx0_a, reg;
+       long y, tx0_c;
+
+       if (final_candidate == 0xFF) {
+               return;
+       } else if (iqk_ok) {
+               oldval_0 = (rtl_get_bbreg(hw, ROFDM0_XATXIQIMBALANCE,
+                                         MASKDWORD) >> 22) & 0x3FF;
+               x = result[final_candidate][0];
+               if ((x & 0x00000200) != 0)
+                       x = x | 0xFFFFFC00;
+               tx0_a = (x * oldval_0) >> 8;
+               rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x3FF, tx0_a);
+               rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(31),
+                             ((x * oldval_0 >> 7) & 0x1));
+               y = result[final_candidate][1];
+               if ((y & 0x00000200) != 0)
+                       y = y | 0xFFFFFC00;
+               tx0_c = (y * oldval_0) >> 8;
+               rtl_set_bbreg(hw, ROFDM0_XCTXAFE, 0xF0000000,
+                             ((tx0_c & 0x3C0) >> 6));
+               rtl_set_bbreg(hw, ROFDM0_XATXIQIMBALANCE, 0x003F0000,
+                             (tx0_c & 0x3F));
+               rtl_set_bbreg(hw, ROFDM0_ECCATHRESHOLD, BIT(29),
+                             ((y * oldval_0 >> 7) & 0x1));
+               if (btxonly)
+                       return;
+               reg = result[final_candidate][2];
+               rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0x3FF, reg);
+               reg = result[final_candidate][3] & 0x3F;
+               rtl_set_bbreg(hw, ROFDM0_XARXIQIMBALANCE, 0xFC00, reg);
+               reg = (result[final_candidate][3] >> 6) & 0xF;
+               rtl_set_bbreg(hw, 0xca0, 0xF0000000, reg);
+       }
+}
+
+static void phy_save_adda_regs(struct ieee80211_hw *hw,
+                                              u32 *addareg, u32 *addabackup,
+                                              u32 registernum)
+{
+       u32 i;
+
+       for (i = 0; i < registernum; i++)
+               addabackup[i] = rtl_get_bbreg(hw, addareg[i], MASKDWORD);
+}
+
+static void phy_save_mac_regs(struct ieee80211_hw *hw, u32 *macreg,
+                             u32 *macbackup)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 i;
+
+       for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+               macbackup[i] = rtl_read_byte(rtlpriv, macreg[i]);
+       macbackup[i] = rtl_read_dword(rtlpriv, macreg[i]);
+}
+
+static void phy_reload_adda_regs(struct ieee80211_hw *hw, u32 *addareg,
+                                u32 *addabackup, u32 regiesternum)
+{
+       u32 i;
+
+       for (i = 0; i < regiesternum; i++)
+               rtl_set_bbreg(hw, addareg[i], MASKDWORD, addabackup[i]);
+}
+
+static void phy_reload_mac_regs(struct ieee80211_hw *hw, u32 *macreg,
+                               u32 *macbackup)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 i;
+
+       for (i = 0; i < (IQK_MAC_REG_NUM - 1); i++)
+               rtl_write_byte(rtlpriv, macreg[i], (u8) macbackup[i]);
+       rtl_write_dword(rtlpriv, macreg[i], macbackup[i]);
+}
+
+static void _rtl8723ae_phy_path_adda_on(struct ieee80211_hw *hw,
+                                       u32 *addareg, bool is_patha_on,
+                                       bool is2t)
+{
+       u32 pathOn;
+       u32 i;
+
+       pathOn = is_patha_on ? 0x04db25a4 : 0x0b1b25a4;
+       if (false == is2t) {
+               pathOn = 0x0bdb25a0;
+               rtl_set_bbreg(hw, addareg[0], MASKDWORD, 0x0b1b25a0);
+       } else {
+               rtl_set_bbreg(hw, addareg[0], MASKDWORD, pathOn);
+       }
+
+       for (i = 1; i < IQK_ADDA_REG_NUM; i++)
+               rtl_set_bbreg(hw, addareg[i], MASKDWORD, pathOn);
+}
+
+static void _rtl8723ae_phy_mac_setting_calibration(struct ieee80211_hw *hw,
+                                                  u32 *macreg, u32 *macbackup)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 i = 0;
+
+       rtl_write_byte(rtlpriv, macreg[i], 0x3F);
+
+       for (i = 1; i < (IQK_MAC_REG_NUM - 1); i++)
+               rtl_write_byte(rtlpriv, macreg[i],
+                              (u8) (macbackup[i] & (~BIT(3))));
+       rtl_write_byte(rtlpriv, macreg[i], (u8) (macbackup[i] & (~BIT(5))));
+}
+
+static void _rtl8723ae_phy_path_a_standby(struct ieee80211_hw *hw)
+{
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x0);
+       rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+}
+
+static void _rtl8723ae_phy_pi_mode_switch(struct ieee80211_hw *hw, bool pi_mode)
+{
+       u32 mode;
+
+       mode = pi_mode ? 0x01000100 : 0x01000000;
+       rtl_set_bbreg(hw, 0x820, MASKDWORD, mode);
+       rtl_set_bbreg(hw, 0x828, MASKDWORD, mode);
+}
+
+static bool phy_simularity_comp(struct ieee80211_hw *hw, long result[][8],
+                               u8 c1, u8 c2)
+{
+       u32 i, j, diff, simularity_bitmap, bound;
+
+       u8 final_candidate[2] = { 0xFF, 0xFF };
+       bool bresult = true;
+
+       bound = 4;
+
+       simularity_bitmap = 0;
+
+       for (i = 0; i < bound; i++) {
+               diff = (result[c1][i] > result[c2][i]) ?
+                   (result[c1][i] - result[c2][i]) :
+                   (result[c2][i] - result[c1][i]);
+
+               if (diff > MAX_TOLERANCE) {
+                       if ((i == 2 || i == 6) && !simularity_bitmap) {
+                               if (result[c1][i] + result[c1][i + 1] == 0)
+                                       final_candidate[(i / 4)] = c2;
+                               else if (result[c2][i] + result[c2][i + 1] == 0)
+                                       final_candidate[(i / 4)] = c1;
+                               else
+                                       simularity_bitmap = simularity_bitmap |
+                                           (1 << i);
+                       } else
+                               simularity_bitmap =
+                                   simularity_bitmap | (1 << i);
+               }
+       }
+
+       if (simularity_bitmap == 0) {
+               for (i = 0; i < (bound / 4); i++) {
+                       if (final_candidate[i] != 0xFF) {
+                               for (j = i * 4; j < (i + 1) * 4 - 2; j++)
+                                       result[3][j] =
+                                           result[final_candidate[i]][j];
+                               bresult = false;
+                       }
+               }
+               return bresult;
+       } else if (!(simularity_bitmap & 0x0F)) {
+               for (i = 0; i < 4; i++)
+                       result[3][i] = result[c1][i];
+               return false;
+       } else {
+               return false;
+       }
+
+}
+
+static void _rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw,
+                                       long result[][8], u8 t, bool is2t)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u32 i;
+       u8 patha_ok, pathb_ok;
+       u32 adda_reg[IQK_ADDA_REG_NUM] = {
+               0x85c, 0xe6c, 0xe70, 0xe74,
+               0xe78, 0xe7c, 0xe80, 0xe84,
+               0xe88, 0xe8c, 0xed0, 0xed4,
+               0xed8, 0xedc, 0xee0, 0xeec
+       };
+       u32 iqk_mac_reg[IQK_MAC_REG_NUM] = {
+               0x522, 0x550, 0x551, 0x040
+       };
+       const u32 retrycount = 2;
+       u32 bbvalue;
+
+       if (t == 0) {
+               bbvalue = rtl_get_bbreg(hw, 0x800, MASKDWORD);
+
+               phy_save_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
+               phy_save_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+       }
+       _rtl8723ae_phy_path_adda_on(hw, adda_reg, true, is2t);
+       if (t == 0) {
+               rtlphy->rfpi_enable = (u8) rtl_get_bbreg(hw,
+                                                RFPGA0_XA_HSSIPARAMETER1,
+                                                BIT(8));
+       }
+
+       if (!rtlphy->rfpi_enable)
+               _rtl8723ae_phy_pi_mode_switch(hw, true);
+       if (t == 0) {
+               rtlphy->reg_c04 = rtl_get_bbreg(hw, 0xc04, MASKDWORD);
+               rtlphy->reg_c08 = rtl_get_bbreg(hw, 0xc08, MASKDWORD);
+               rtlphy->reg_874 = rtl_get_bbreg(hw, 0x874, MASKDWORD);
+       }
+       rtl_set_bbreg(hw, 0xc04, MASKDWORD, 0x03a05600);
+       rtl_set_bbreg(hw, 0xc08, MASKDWORD, 0x000800e4);
+       rtl_set_bbreg(hw, 0x874, MASKDWORD, 0x22204000);
+       if (is2t) {
+               rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00010000);
+               rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00010000);
+       }
+       _rtl8723ae_phy_mac_setting_calibration(hw, iqk_mac_reg,
+                                           rtlphy->iqk_mac_backup);
+       rtl_set_bbreg(hw, 0xb68, MASKDWORD, 0x00080000);
+       if (is2t)
+               rtl_set_bbreg(hw, 0xb6c, MASKDWORD, 0x00080000);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0x80800000);
+       rtl_set_bbreg(hw, 0xe40, MASKDWORD, 0x01007c00);
+       rtl_set_bbreg(hw, 0xe44, MASKDWORD, 0x01004800);
+       for (i = 0; i < retrycount; i++) {
+               patha_ok = _rtl8723ae_phy_path_a_iqk(hw, is2t);
+               if (patha_ok == 0x03) {
+                       result[t][0] = (rtl_get_bbreg(hw, 0xe94, MASKDWORD) &
+                                       0x3FF0000) >> 16;
+                       result[t][1] = (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) &
+                                       0x3FF0000) >> 16;
+                       result[t][2] = (rtl_get_bbreg(hw, 0xea4, MASKDWORD) &
+                                       0x3FF0000) >> 16;
+                       result[t][3] = (rtl_get_bbreg(hw, 0xeac, MASKDWORD) &
+                                       0x3FF0000) >> 16;
+                       break;
+               } else if (i == (retrycount - 1) && patha_ok == 0x01)
+
+                       result[t][0] = (rtl_get_bbreg(hw, 0xe94,
+                                       MASKDWORD) & 0x3FF0000) >> 16;
+               result[t][1] =
+                   (rtl_get_bbreg(hw, 0xe9c, MASKDWORD) & 0x3FF0000) >> 16;
+
+       }
+
+       if (is2t) {
+               _rtl8723ae_phy_path_a_standby(hw);
+               _rtl8723ae_phy_path_adda_on(hw, adda_reg, false, is2t);
+               for (i = 0; i < retrycount; i++) {
+                       pathb_ok = _rtl8723ae_phy_path_b_iqk(hw);
+                       if (pathb_ok == 0x03) {
+                               result[t][4] =
+                                   (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) &
+                                    0x3FF0000) >> 16;
+                               result[t][5] =
+                                   (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
+                                    0x3FF0000) >> 16;
+                               result[t][6] =
+                                   (rtl_get_bbreg(hw, 0xec4, MASKDWORD) &
+                                    0x3FF0000) >> 16;
+                               result[t][7] =
+                                   (rtl_get_bbreg(hw, 0xecc, MASKDWORD) &
+                                    0x3FF0000) >> 16;
+                               break;
+                       } else if (i == (retrycount - 1) && pathb_ok == 0x01) {
+                               result[t][4] =
+                                   (rtl_get_bbreg(hw, 0xeb4, MASKDWORD) &
+                                    0x3FF0000) >> 16;
+                       }
+                       result[t][5] = (rtl_get_bbreg(hw, 0xebc, MASKDWORD) &
+                                       0x3FF0000) >> 16;
+               }
+       }
+       rtl_set_bbreg(hw, 0xc04, MASKDWORD, rtlphy->reg_c04);
+       rtl_set_bbreg(hw, 0x874, MASKDWORD, rtlphy->reg_874);
+       rtl_set_bbreg(hw, 0xc08, MASKDWORD, rtlphy->reg_c08);
+       rtl_set_bbreg(hw, 0xe28, MASKDWORD, 0);
+       rtl_set_bbreg(hw, 0x840, MASKDWORD, 0x00032ed3);
+       if (is2t)
+               rtl_set_bbreg(hw, 0x844, MASKDWORD, 0x00032ed3);
+       if (t != 0) {
+               if (!rtlphy->rfpi_enable)
+                       _rtl8723ae_phy_pi_mode_switch(hw, false);
+               phy_reload_adda_regs(hw, adda_reg, rtlphy->adda_backup, 16);
+               phy_reload_mac_regs(hw, iqk_mac_reg, rtlphy->iqk_mac_backup);
+       }
+}
+
+static void _rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw, bool is2t)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u8 tmpreg;
+       u32 rf_a_mode = 0, rf_b_mode = 0, lc_cal;
+
+       tmpreg = rtl_read_byte(rtlpriv, 0xd03);
+
+       if ((tmpreg & 0x70) != 0)
+               rtl_write_byte(rtlpriv, 0xd03, tmpreg & 0x8F);
+       else
+               rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+
+       if ((tmpreg & 0x70) != 0) {
+               rf_a_mode = rtl_get_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS);
+
+               if (is2t)
+                       rf_b_mode = rtl_get_rfreg(hw, RF90_PATH_B, 0x00,
+                                                 MASK12BITS);
+
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS,
+                             (rf_a_mode & 0x8FFFF) | 0x10000);
+
+               if (is2t)
+                       rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
+                                     (rf_b_mode & 0x8FFFF) | 0x10000);
+       }
+       lc_cal = rtl_get_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS);
+
+       rtl_set_rfreg(hw, RF90_PATH_A, 0x18, MASK12BITS, lc_cal | 0x08000);
+
+       mdelay(100);
+
+       if ((tmpreg & 0x70) != 0) {
+               rtl_write_byte(rtlpriv, 0xd03, tmpreg);
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x00, MASK12BITS, rf_a_mode);
+
+               if (is2t)
+                       rtl_set_rfreg(hw, RF90_PATH_B, 0x00, MASK12BITS,
+                                     rf_b_mode);
+       } else {
+               rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+       }
+}
+
+static void _rtl8723ae_phy_set_rfpath_switch(struct ieee80211_hw *hw,
+                                            bool bmain, bool is2t)
+{
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+
+       if (is_hal_stop(rtlhal)) {
+               rtl_set_bbreg(hw, REG_LEDCFG0, BIT(23), 0x01);
+               rtl_set_bbreg(hw, rFPGA0_XAB_RFPARAMETER, BIT(13), 0x01);
+       }
+       if (is2t) {
+               if (bmain)
+                       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+                                     BIT(5) | BIT(6), 0x1);
+               else
+                       rtl_set_bbreg(hw, RFPGA0_XB_RFINTERFACEOE,
+                                     BIT(5) | BIT(6), 0x2);
+       } else {
+               if (bmain)
+                       rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x2);
+               else
+                       rtl_set_bbreg(hw, RFPGA0_XA_RFINTERFACEOE, 0x300, 0x1);
+
+       }
+}
+
+#undef IQK_ADDA_REG_NUM
+#undef IQK_DELAY_TIME
+
+void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       long result[4][8];
+       u8 i, final_candidate;
+       bool patha_ok, pathb_ok;
+       long reg_e94, reg_e9c, reg_ea4, reg_eac, reg_eb4, reg_ebc, reg_ec4,
+           reg_ecc, reg_tmp = 0;
+       bool is12simular, is13simular, is23simular;
+       bool start_conttx = false, singletone = false;
+       u32 iqk_bb_reg[10] = {
+               ROFDM0_XARXIQIMBALANCE,
+               ROFDM0_XBRXIQIMBALANCE,
+               ROFDM0_ECCATHRESHOLD,
+               ROFDM0_AGCRSSITABLE,
+               ROFDM0_XATXIQIMBALANCE,
+               ROFDM0_XBTXIQIMBALANCE,
+               ROFDM0_XCTXIQIMBALANCE,
+               ROFDM0_XCTXAFE,
+               ROFDM0_XDTXAFE,
+               ROFDM0_RXIQEXTANTA
+       };
+
+       if (recovery) {
+               phy_reload_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10);
+               return;
+       }
+       if (start_conttx || singletone)
+               return;
+       for (i = 0; i < 8; i++) {
+               result[0][i] = 0;
+               result[1][i] = 0;
+               result[2][i] = 0;
+               result[3][i] = 0;
+       }
+       final_candidate = 0xff;
+       patha_ok = false;
+       pathb_ok = false;
+       is12simular = false;
+       is23simular = false;
+       is13simular = false;
+       for (i = 0; i < 3; i++) {
+               _rtl8723ae_phy_iq_calibrate(hw, result, i, false);
+               if (i == 1) {
+                       is12simular = phy_simularity_comp(hw, result, 0, 1);
+                       if (is12simular) {
+                               final_candidate = 0;
+                               break;
+                       }
+               }
+               if (i == 2) {
+                       is13simular = phy_simularity_comp(hw, result, 0, 2);
+                       if (is13simular) {
+                               final_candidate = 0;
+                               break;
+                       }
+                       is23simular = phy_simularity_comp(hw, result, 1, 2);
+                       if (is23simular) {
+                               final_candidate = 1;
+                       } else {
+                               for (i = 0; i < 8; i++)
+                                       reg_tmp += result[3][i];
+
+                               if (reg_tmp != 0)
+                                       final_candidate = 3;
+                               else
+                                       final_candidate = 0xFF;
+                       }
+               }
+       }
+       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 (final_candidate != 0xff) {
+               rtlphy->reg_e94 = reg_e94 = result[final_candidate][0];
+               rtlphy->reg_e9c = reg_e9c = result[final_candidate][1];
+               reg_ea4 = result[final_candidate][2];
+               reg_eac = result[final_candidate][3];
+               rtlphy->reg_eb4 = reg_eb4 = result[final_candidate][4];
+               rtlphy->reg_ebc = reg_ebc = result[final_candidate][5];
+               reg_ec4 = result[final_candidate][6];
+               reg_ecc = result[final_candidate][7];
+               patha_ok = pathb_ok = true;
+       } else {
+               rtlphy->reg_e94 = rtlphy->reg_eb4 = 0x100;
+               rtlphy->reg_e9c = rtlphy->reg_ebc = 0x0;
+       }
+       if (reg_e94 != 0) /*&&(reg_ea4 != 0) */
+               phy_path_a_fill_iqk_matrix(hw, patha_ok, result,
+                                          final_candidate, (reg_ea4 == 0));
+       phy_save_adda_regs(hw, iqk_bb_reg, rtlphy->iqk_bb_backup, 10);
+}
+
+void rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw)
+{
+       bool start_conttx = false, singletone = false;
+
+       if (start_conttx || singletone)
+               return;
+       _rtl8723ae_phy_lc_calibrate(hw, false);
+}
+
+void rtl8723ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain)
+{
+       _rtl8723ae_phy_set_rfpath_switch(hw, bmain, false);
+}
+
+bool rtl8723ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       bool postprocessing = false;
+
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                "-->IO Cmd(%#x), set_io_inprogress(%d)\n",
+                iotype, rtlphy->set_io_inprogress);
+       do {
+               switch (iotype) {
+               case IO_CMD_RESUME_DM_BY_SCAN:
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                                "[IO CMD] Resume DM after scan.\n");
+                       postprocessing = true;
+                       break;
+               case IO_CMD_PAUSE_DM_BY_SCAN:
+                       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                                "[IO CMD] Pause DM before scan.\n");
+                       postprocessing = true;
+                       break;
+               default:
+                       RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                                "switch case not process\n");
+                       break;
+               }
+       } while (false);
+       if (postprocessing && !rtlphy->set_io_inprogress) {
+               rtlphy->set_io_inprogress = true;
+               rtlphy->current_io_type = iotype;
+       } else {
+               return false;
+       }
+       rtl8723ae_phy_set_io(hw);
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE, "<--IO Type(%#x)\n", iotype);
+       return true;
+}
+
+static void rtl8723ae_phy_set_io(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct dig_t *dm_digtable = &rtlpriv->dm_digtable;
+
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                "--->Cmd(%#x), set_io_inprogress(%d)\n",
+                rtlphy->current_io_type, rtlphy->set_io_inprogress);
+       switch (rtlphy->current_io_type) {
+       case IO_CMD_RESUME_DM_BY_SCAN:
+               dm_digtable->cur_igvalue = rtlphy->initgain_backup.xaagccore1;
+               rtl8723ae_dm_write_dig(hw);
+               rtl8723ae_phy_set_txpower_level(hw, rtlphy->current_channel);
+               break;
+       case IO_CMD_PAUSE_DM_BY_SCAN:
+               rtlphy->initgain_backup.xaagccore1 = dm_digtable->cur_igvalue;
+               dm_digtable->cur_igvalue = 0x17;
+               rtl8723ae_dm_write_dig(hw);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not process\n");
+               break;
+       }
+       rtlphy->set_io_inprogress = false;
+       RT_TRACE(rtlpriv, COMP_CMD, DBG_TRACE,
+                "<---(%#x)\n", rtlphy->current_io_type);
+}
+
+static void rtl8723ae_phy_set_rf_on(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x2b);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+       rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+       rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+}
+
+static void _rtl8723ae_phy_set_rf_sleep(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 u4b_tmp;
+       u8 delay = 5;
+
+       rtl_write_byte(rtlpriv, REG_TXPAUSE, 0xFF);
+       rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+       rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
+       u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
+       while (u4b_tmp != 0 && delay > 0) {
+               rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x0);
+               rtl_set_rfreg(hw, RF90_PATH_A, 0x00, RFREG_OFFSET_MASK, 0x00);
+               rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x40);
+               u4b_tmp = rtl_get_rfreg(hw, RF90_PATH_A, 0, RFREG_OFFSET_MASK);
+               delay--;
+       }
+       if (delay == 0) {
+               rtl_write_byte(rtlpriv, REG_APSD_CTRL, 0x00);
+               rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+               rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE3);
+               rtl_write_byte(rtlpriv, REG_TXPAUSE, 0x00);
+               RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
+                        "Switch RF timeout !!!.\n");
+               return;
+       }
+       rtl_write_byte(rtlpriv, REG_SYS_FUNC_EN, 0xE2);
+       rtl_write_byte(rtlpriv, REG_SPS0_CTRL, 0x22);
+}
+
+static bool _rtl8723ae_phy_set_rf_power_state(struct ieee80211_hw *hw,
+                                             enum rf_pwrstate rfpwr_state)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       struct rtl8192_tx_ring *ring = NULL;
+       bool bresult = true;
+       u8 i, queue_id;
+
+       switch (rfpwr_state) {
+       case ERFON:
+               if ((ppsc->rfpwr_state == ERFOFF) &&
+                   RT_IN_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC)) {
+                       bool rtstatus;
+                       u32 InitializeCount = 0;
+                       do {
+                               InitializeCount++;
+                               RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                                        "IPS Set eRf nic enable\n");
+                               rtstatus = rtl_ps_enable_nic(hw);
+                       } while ((rtstatus != true) && (InitializeCount < 10));
+                       RT_CLEAR_PS_LEVEL(ppsc,
+                                         RT_RF_OFF_LEVL_HALT_NIC);
+               } else {
+                       RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                                "Set ERFON sleeped:%d ms\n",
+                                jiffies_to_msecs(jiffies -
+                                ppsc->last_sleep_jiffies));
+                       ppsc->last_awake_jiffies = jiffies;
+                       rtl8723ae_phy_set_rf_on(hw);
+               }
+               if (mac->link_state == MAC80211_LINKED) {
+                       rtlpriv->cfg->ops->led_control(hw,
+                                       LED_CTL_LINK);
+               } else {
+                       rtlpriv->cfg->ops->led_control(hw,
+                                       LED_CTL_NO_LINK);
+               }
+               break;
+       case ERFOFF:
+               if (ppsc->reg_rfps_level & RT_RF_OFF_LEVL_HALT_NIC) {
+                       RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                                "IPS Set eRf nic disable\n");
+                       rtl_ps_disable_nic(hw);
+                       RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
+               } else {
+                       if (ppsc->rfoff_reason == RF_CHANGE_BY_IPS) {
+                               rtlpriv->cfg->ops->led_control(hw,
+                                       LED_CTL_NO_LINK);
+                       } else {
+                               rtlpriv->cfg->ops->led_control(hw,
+                                       LED_CTL_POWER_OFF);
+                       }
+               }
+               break;
+       case ERFSLEEP:
+               if (ppsc->rfpwr_state == ERFOFF)
+                       break;
+               for (queue_id = 0, i = 0;
+                    queue_id < RTL_PCI_MAX_TX_QUEUE_COUNT;) {
+                       ring = &pcipriv->dev.tx_ring[queue_id];
+                       if (skb_queue_len(&ring->queue) == 0) {
+                               queue_id++;
+                               continue;
+                       } else {
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                        "eRf Off/Sleep: %d times TcbBusyQueue[%d] =%d before doze!\n",
+                                        (i + 1), queue_id,
+                                        skb_queue_len(&ring->queue));
+
+                               udelay(10);
+                               i++;
+                       }
+                       if (i >= MAX_DOZE_WAITING_TIMES_9x) {
+                               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
+                                        "\n ERFSLEEP: %d times TcbBusyQueue[%d] = %d !\n",
+                                        MAX_DOZE_WAITING_TIMES_9x,
+                                        queue_id,
+                                        skb_queue_len(&ring->queue));
+                               break;
+                       }
+               }
+               RT_TRACE(rtlpriv, COMP_RF, DBG_DMESG,
+                        "Set ERFSLEEP awaked:%d ms\n",
+                        jiffies_to_msecs(jiffies - ppsc->last_awake_jiffies));
+               ppsc->last_sleep_jiffies = jiffies;
+               _rtl8723ae_phy_set_rf_sleep(hw);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "switch case not processed\n");
+               bresult = false;
+               break;
+       }
+       if (bresult)
+               ppsc->rfpwr_state = rfpwr_state;
+       return bresult;
+}
+
+bool rtl8723ae_phy_set_rf_power_state(struct ieee80211_hw *hw,
+                                     enum rf_pwrstate rfpwr_state)
+{
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       bool bresult = false;
+
+       if (rfpwr_state == ppsc->rfpwr_state)
+               return bresult;
+       bresult = _rtl8723ae_phy_set_rf_power_state(hw, rfpwr_state);
+       return bresult;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h b/drivers/net/wireless/rtlwifi/rtl8723ae/phy.h
new file mode 100644 (file)
index 0000000..e7a59eb
--- /dev/null
@@ -0,0 +1,224 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL92C_PHY_H__
+#define __RTL92C_PHY_H__
+
+#define MAX_PRECMD_CNT                         16
+#define MAX_RFDEPENDCMD_CNT                    16
+#define MAX_POSTCMD_CNT                                16
+
+#define MAX_DOZE_WAITING_TIMES_9x              64
+
+#define RT_CANNOT_IO(hw)                       false
+#define HIGHPOWER_RADIOA_ARRAYLEN              22
+
+#define MAX_TOLERANCE                          5
+#define        IQK_DELAY_TIME                          1
+
+#define        APK_BB_REG_NUM                          5
+#define        APK_AFE_REG_NUM                         16
+#define        APK_CURVE_REG_NUM                       4
+#define        PATH_NUM                                2
+
+#define LOOP_LIMIT                             5
+#define MAX_STALL_TIME                         50
+#define AntennaDiversityValue                  0x80
+#define MAX_TXPWR_IDX_NMODE_92S                        63
+#define Reset_Cnt_Limit                                3
+
+#define IQK_MAC_REG_NUM                                4
+
+#define RF6052_MAX_PATH                                2
+
+#define CT_OFFSET_MAC_ADDR                     0X16
+
+#define CT_OFFSET_CCK_TX_PWR_IDX               0x5A
+#define CT_OFFSET_HT401S_TX_PWR_IDX            0x60
+#define CT_OFFSET_HT402S_TX_PWR_IDX_DIFF       0x66
+#define CT_OFFSET_HT20_TX_PWR_IDX_DIFF         0x69
+#define CT_OFFSET_OFDM_TX_PWR_IDX_DIFF         0x6C
+
+#define CT_OFFSET_HT40_MAX_PWR_OFFSET          0x6F
+#define CT_OFFSET_HT20_MAX_PWR_OFFSET          0x72
+
+#define CT_OFFSET_CHANNEL_PLAH                 0x75
+#define CT_OFFSET_THERMAL_METER                        0x78
+#define CT_OFFSET_RF_OPTION                    0x79
+#define CT_OFFSET_VERSION                      0x7E
+#define CT_OFFSET_CUSTOMER_ID                  0x7F
+
+#define RTL92C_MAX_PATH_NUM                    2
+
+enum swchnlcmd_id {
+       CMDID_END,
+       CMDID_SET_TXPOWEROWER_LEVEL,
+       CMDID_BBREGWRITE10,
+       CMDID_WRITEPORT_ULONG,
+       CMDID_WRITEPORT_USHORT,
+       CMDID_WRITEPORT_UCHAR,
+       CMDID_RF_WRITEREG,
+};
+
+struct swchnlcmd {
+       enum swchnlcmd_id cmdid;
+       u32 para1;
+       u32 para2;
+       u32 msdelay;
+};
+
+enum hw90_block_e {
+       HW90_BLOCK_MAC = 0,
+       HW90_BLOCK_PHY0 = 1,
+       HW90_BLOCK_PHY1 = 2,
+       HW90_BLOCK_RF = 3,
+       HW90_BLOCK_MAXIMUM = 4,
+};
+
+enum baseband_config_type {
+       BASEBAND_CONFIG_PHY_REG = 0,
+       BASEBAND_CONFIG_AGC_TAB = 1,
+};
+
+enum ra_offset_area {
+       RA_OFFSET_LEGACY_OFDM1,
+       RA_OFFSET_LEGACY_OFDM2,
+       RA_OFFSET_HT_OFDM1,
+       RA_OFFSET_HT_OFDM2,
+       RA_OFFSET_HT_OFDM3,
+       RA_OFFSET_HT_OFDM4,
+       RA_OFFSET_HT_CCK,
+};
+
+enum antenna_path {
+       ANTENNA_NONE,
+       ANTENNA_D,
+       ANTENNA_C,
+       ANTENNA_CD,
+       ANTENNA_B,
+       ANTENNA_BD,
+       ANTENNA_BC,
+       ANTENNA_BCD,
+       ANTENNA_A,
+       ANTENNA_AD,
+       ANTENNA_AC,
+       ANTENNA_ACD,
+       ANTENNA_AB,
+       ANTENNA_ABD,
+       ANTENNA_ABC,
+       ANTENNA_ABCD
+};
+
+struct r_antenna_select_ofdm {
+       u32 r_tx_antenna:4;
+       u32 r_ant_l:4;
+       u32 r_ant_non_ht:4;
+       u32 r_ant_ht1:4;
+       u32 r_ant_ht2:4;
+       u32 r_ant_ht_s1:4;
+       u32 r_ant_non_ht_s1:4;
+       u32 ofdm_txsc:2;
+       u32 reserved:2;
+};
+
+struct r_antenna_select_cck {
+       u8 r_cckrx_enable_2:2;
+       u8 r_cckrx_enable:2;
+       u8 r_ccktx_enable:4;
+};
+
+struct efuse_contents {
+       u8 mac_addr[ETH_ALEN];
+       u8 cck_tx_power_idx[6];
+       u8 ht40_1s_tx_power_idx[6];
+       u8 ht40_2s_tx_power_idx_diff[3];
+       u8 ht20_tx_power_idx_diff[3];
+       u8 ofdm_tx_power_idx_diff[3];
+       u8 ht40_max_power_offset[3];
+       u8 ht20_max_power_offset[3];
+       u8 channel_plan;
+       u8 thermal_meter;
+       u8 rf_option[5];
+       u8 version;
+       u8 oem_id;
+       u8 regulatory;
+};
+
+struct tx_power_struct {
+       u8 cck[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 ht40_1s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 ht40_2s[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 ht20_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 legacy_ht_diff[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 legacy_ht_txpowerdiff;
+       u8 groupht20[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 groupht40[RTL92C_MAX_PATH_NUM][CHANNEL_MAX_NUMBER];
+       u8 pwrgroup_cnt;
+       u32 mcs_original_offset[4][16];
+};
+
+extern u32 rtl8723ae_phy_query_bb_reg(struct ieee80211_hw *hw,
+                                     u32 regaddr, u32 bitmask);
+extern void rtl8723ae_phy_set_bb_reg(struct ieee80211_hw *hw,
+                                    u32 regaddr, u32 bitmask, u32 data);
+extern u32 rtl8723ae_phy_query_rf_reg(struct ieee80211_hw *hw,
+                                     enum radio_path rfpath, u32 regaddr,
+                                     u32 bitmask);
+extern void rtl8723ae_phy_set_rf_reg(struct ieee80211_hw *hw,
+                                    enum radio_path rfpath, u32 regaddr,
+                                    u32 bitmask, u32 data);
+extern bool rtl8723ae_phy_mac_config(struct ieee80211_hw *hw);
+extern bool rtl8723ae_phy_bb_config(struct ieee80211_hw *hw);
+extern bool rtl8723ae_phy_rf_config(struct ieee80211_hw *hw);
+extern bool rtl92c_phy_config_rf_with_feaderfile(struct ieee80211_hw *hw,
+                                                enum radio_path rfpath);
+extern void rtl8723ae_phy_get_hw_reg_originalvalue(struct ieee80211_hw *hw);
+extern void rtl8723ae_phy_get_txpower_level(struct ieee80211_hw *hw,
+                                           long *powerlevel);
+extern void rtl8723ae_phy_set_txpower_level(struct ieee80211_hw *hw,
+                                           u8 channel);
+extern bool rtl8723ae_phy_update_txpower_dbm(struct ieee80211_hw *hw,
+                                            long power_indbm);
+extern void rtl8723ae_phy_scan_operation_backup(struct ieee80211_hw *hw,
+                                               u8 operation);
+extern void rtl8723ae_phy_set_bw_mode_callback(struct ieee80211_hw *hw);
+extern void rtl8723ae_phy_set_bw_mode(struct ieee80211_hw *hw,
+                                     enum nl80211_channel_type ch_type);
+extern void rtl8723ae_phy_sw_chnl_callback(struct ieee80211_hw *hw);
+extern u8 rtl8723ae_phy_sw_chnl(struct ieee80211_hw *hw);
+extern void rtl8723ae_phy_iq_calibrate(struct ieee80211_hw *hw, bool recovery);
+void rtl8723ae_phy_lc_calibrate(struct ieee80211_hw *hw);
+void rtl8723ae_phy_set_rfpath_switch(struct ieee80211_hw *hw, bool bmain);
+bool rtl8723ae_phy_config_rf_with_headerfile(struct ieee80211_hw *hw,
+                                            enum radio_path rfpath);
+bool rtl8723ae_phy_set_io_cmd(struct ieee80211_hw *hw, enum io_type iotype);
+extern bool rtl8723ae_phy_set_rf_power_state(struct ieee80211_hw *hw,
+                                            enum rf_pwrstate rfpwr_state);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.c
new file mode 100644 (file)
index 0000000..df6ca9a
--- /dev/null
@@ -0,0 +1,109 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseqcmd.h"
+#include "pwrseq.h"
+
+/* drivers should parse arrays below and do the corresponding actions */
+
+/*3 Power on  Array*/
+struct wlan_pwr_cfg rtl8723A_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STPS
+                                       + RTL8723A_TRANS_END_STPS] = {
+       RTL8723A_TRANS_CARDEMU_TO_ACT,
+       RTL8723A_TRANS_END
+};
+
+/*3Radio off GPIO Array */
+struct wlan_pwr_cfg rtl8723A_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                       + RTL8723A_TRANS_END_STPS] = {
+       RTL8723A_TRANS_ACT_TO_CARDEMU,
+       RTL8723A_TRANS_END
+};
+
+/*3Card Disable Array*/
+struct wlan_pwr_cfg
+rtl8723A_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                         + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
+                         + RTL8723A_TRANS_END_STPS] = {
+       RTL8723A_TRANS_ACT_TO_CARDEMU,
+       RTL8723A_TRANS_CARDEMU_TO_CARDDIS,
+       RTL8723A_TRANS_END
+};
+
+/*3 Card Enable Array*/
+struct wlan_pwr_cfg rtl8723A_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                       + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
+                                       + RTL8723A_TRANS_END_STPS] = {
+       RTL8723A_TRANS_CARDDIS_TO_CARDEMU,
+       RTL8723A_TRANS_CARDEMU_TO_ACT,
+       RTL8723A_TRANS_END
+};
+
+/*3Suspend Array*/
+struct wlan_pwr_cfg rtl8723A_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                       + RTL8723A_TRANS_CARDEMU_TO_SUS_STPS
+                                       + RTL8723A_TRANS_END_STPS] = {
+       RTL8723A_TRANS_ACT_TO_CARDEMU,
+       RTL8723A_TRANS_CARDEMU_TO_SUS,
+       RTL8723A_TRANS_END
+};
+
+/*3 Resume Array*/
+struct wlan_pwr_cfg rtl8723A_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                       + RTL8723A_TRANS_CARDEMU_TO_SUS_STPS
+                                       + RTL8723A_TRANS_END_STPS] = {
+       RTL8723A_TRANS_SUS_TO_CARDEMU,
+       RTL8723A_TRANS_CARDEMU_TO_ACT,
+       RTL8723A_TRANS_END
+};
+
+/*3HWPDN Array*/
+struct wlan_pwr_cfg rtl8723A_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                               + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
+                               + RTL8723A_TRANS_END_STPS] = {
+       RTL8723A_TRANS_ACT_TO_CARDEMU,
+       RTL8723A_TRANS_CARDEMU_TO_PDN,
+       RTL8723A_TRANS_END
+};
+
+/*3 Enter LPS */
+struct wlan_pwr_cfg rtl8723A_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STPS
+                                       + RTL8723A_TRANS_END_STPS] = {
+       /*FW behavior*/
+       RTL8723A_TRANS_ACT_TO_LPS,
+       RTL8723A_TRANS_END
+};
+
+/*3 Leave LPS */
+struct wlan_pwr_cfg rtl8723A_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STPS
+                                       + RTL8723A_TRANS_END_STPS] = {
+       /*FW behavior*/
+       RTL8723A_TRANS_LPS_TO_ACT,
+       RTL8723A_TRANS_END
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseq.h
new file mode 100644 (file)
index 0000000..7a46f9f
--- /dev/null
@@ -0,0 +1,322 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_PWRSEQ_H__
+#define __RTL8723E_PWRSEQ_H__
+
+#include "pwrseqcmd.h"
+/*
+       Check document WM-20110607-Paul-RTL8723A_Power_Architecture-R02.vsd
+       There are 6 HW Power States:
+       0: POFF--Power Off
+       1: PDN--Power Down
+       2: CARDEMU--Card Emulation
+       3: ACT--Active Mode
+       4: LPS--Low Power State
+       5: SUS--Suspend
+
+       The transision from different states are defined below
+       TRANS_CARDEMU_TO_ACT
+       TRANS_ACT_TO_CARDEMU
+       TRANS_CARDEMU_TO_SUS
+       TRANS_SUS_TO_CARDEMU
+       TRANS_CARDEMU_TO_PDN
+       TRANS_ACT_TO_LPS
+       TRANS_LPS_TO_ACT
+
+       TRANS_END
+*/
+
+#define        RTL8723A_TRANS_CARDEMU_TO_ACT_STPS      10
+#define        RTL8723A_TRANS_ACT_TO_CARDEMU_STPS      10
+#define        RTL8723A_TRANS_CARDEMU_TO_SUS_STPS      10
+#define        RTL8723A_TRANS_SUS_TO_CARDEMU_STPS      10
+#define        RTL8723A_TRANS_CARDEMU_TO_PDN_STPS      10
+#define        RTL8723A_TRANS_PDN_TO_CARDEMU_STPS      10
+#define        RTL8723A_TRANS_ACT_TO_LPS_STPS          15
+#define        RTL8723A_TRANS_LPS_TO_ACT_STPS          15
+#define        RTL8723A_TRANS_END_STPS                 1
+
+
+#define RTL8723A_TRANS_CARDEMU_TO_ACT                                  \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, \
+        *  comments here*/                                             \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), 0},            \
+               /* disable SW LPS 0x04[10]=0*/                          \
+       {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), BIT(1)},     \
+               /* wait till 0x04[17] = 1    power ready*/              \
+       {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},       \
+               /* release WLON reset  0x04[16]=1*/                     \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},            \
+               /* disable HWPDN 0x04[15]=0*/                           \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, (BIT(4)|BIT(3)), 0},   \
+       /* disable WL suspend*/                                         \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), BIT(0)},       \
+               /* polling until return 0*/                             \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(0), 0}
+
+#define RTL8723A_TRANS_ACT_TO_CARDEMU                                  \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, \
+        *  comments here*/                                             \
+       {0x001F, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0},              \
+               /*0x1F[7:0] = 0 turn off RF*/                           \
+       {0x004E, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0},            \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},       \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(1), 0}
+
+#define RTL8723A_TRANS_CARDEMU_TO_SUS                                  \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, \
+        *  comments here*/                                             \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4)|BIT(3),         \
+               (BIT(4)|BIT(3))},                                       \
+               /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/      \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK |   \
+               PWR_INTF_SDIO_MSK,                                      \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},\
+                /*0x04[12:11] = 2b'01 enable WL suspend*/              \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+               PWR_BASEADDR_MAC,                                       \
+               PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)|BIT(4)},           \
+                /*0x04[12:11] = 2b'11 enable WL suspend for PCIe*/     \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+               PWR_BASEADDR_SDIO,                                      \
+               PWR_CMD_WRITE, BIT(0), BIT(0)},                         \
+               /*Set SDIO suspend local register*/                     \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+               PWR_BASEADDR_SDIO,                                      \
+               PWR_CMD_POLLING, BIT(1), 0}                             \
+               /*wait power state to suspend*/
+
+#define RTL8723A_TRANS_SUS_TO_CARDEMU                                  \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+               PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},           \
+               /*Set SDIO suspend local register*/                     \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+               PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},    \
+               /*wait power state to suspend*/                         \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0}      \
+               /*0x04[12:11] = 2b'01enable WL suspend*/
+
+#define RTL8723A_TRANS_CARDEMU_TO_CARDDIS                              \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK,                      \
+       PWR_INTF_USB_MSK|PWR_INTF_SDIO_MSK,                             \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), BIT(3)},\
+               /*0x04[12:11] = 2b'01 enable WL suspend*/               \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(2), BIT(2)},       \
+               /*0x04[10] = 1, enable SW LPS*/                         \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+               PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), BIT(0)},      \
+               /*Set SDIO suspend local register*/                     \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+               PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), 0}          \
+               /*wait power state to suspend*/
+
+#define RTL8723A_TRANS_CARDDIS_TO_CARDEMU                              \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+               PWR_BASEADDR_SDIO, PWR_CMD_WRITE, BIT(0), 0},           \
+               /*Set SDIO suspend local register*/                     \
+       {0x0086, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+               PWR_BASEADDR_SDIO, PWR_CMD_POLLING, BIT(1), BIT(1)},    \
+               /*wait power state to suspend*/                         \
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(3)|BIT(4), 0},     \
+               /*0x04[12:11] = 2b'00enable WL suspend*/                \
+       {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}               \
+               /*PCIe DMA start*/
+
+#define RTL8723A_TRANS_CARDEMU_TO_PDN                                  \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+       {0x0006, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},            \
+               /* 0x04[16] = 0*/\
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), BIT(7)}        \
+               /* 0x04[15] = 1*/
+
+#define RTL8723A_TRANS_PDN_TO_CARDEMU                                  \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+       {0x0005, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(7), 0}             \
+               /* 0x04[15] = 0*/
+
+#define RTL8723A_TRANS_ACT_TO_LPS                                      \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+       {0x0301, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},           \
+               /*PCIe DMA stop*/                                       \
+       {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x7F},           \
+               /*Tx Pause*/                                            \
+       {0x05F8, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},            \
+               /*Should be zero if no packet is transmitting*/         \
+       {0x05F9, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},            \
+               /*Should be zero if no packet is transmitting*/         \
+       {0x05FA, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},            \
+               /*Should be zero if no packet is transmitting*/         \
+       {0x05FB, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_POLLING, 0xFF, 0},            \
+               /*Should be zero if no packet is transmitting*/         \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(0), 0},            \
+               /*CCK and OFDM are disabled,and clock are gated*/       \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_US},   \
+               /*Delay 1us*/                                           \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},            \
+               /*Whole BB is reset*/                                   \
+       {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x3F},           \
+               /*Reset MAC TRX*/                                       \
+       {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), 0},            \
+               /*check if removed later*/                              \
+       {0x0553, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(5), BIT(5)}        \
+               /*Respond TxOK to scheduler*/
+
+#define RTL8723A_TRANS_LPS_TO_ACT                                      \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+       {0x0080, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_SDIO_MSK,   \
+                PWR_BASEADDR_SDIO, PWR_CMD_WRITE, 0xFF, 0x84},         \
+                /*SDIO RPWM*/                                          \
+       {0xFE58, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_USB_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},           \
+               /*USB RPWM*/                                            \
+       {0x0361, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_PCI_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0x84},           \
+               /*PCIe RPWM*/                                           \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+                PWR_BASEADDR_MAC, PWR_CMD_DELAY, 0, PWRSEQ_DELAY_MS},  \
+               /*Delay*/                                               \
+       {0x0008, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(4), 0},            \
+               /* 0x08[4] = 0 switch TSF to 40M*/                      \
+       {0x0109, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_POLLING, BIT(7), 0},          \
+               /*Polling 0x109[7]=0  TSF in 40M*/                      \
+       {0x0029, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(6)|BIT(7), 0},     \
+               /*.     0x29[7:6] = 2b'00        enable BB clock*/      \
+       {0x0101, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1), BIT(1)},       \
+               /*.     0x101[1] = 1*/                                  \
+       {0x0100, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0xFF},           \
+               /* 0x100[7:0] = 0xFF enable WMAC TRX*/                  \
+       {0x0002, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, BIT(1)|BIT(0),         \
+               BIT(1)|BIT(0)},                                         \
+               /* 0x02[1:0] = 2b'11  enable BB macro*/                 \
+       {0x0522, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+               PWR_BASEADDR_MAC, PWR_CMD_WRITE, 0xFF, 0}               \
+               /*.     0x522 = 0*/
+
+#define RTL8723A_TRANS_END                                             \
+       /* format */                                                    \
+       /* { offset, cut_msk, fab_msk|interface_msk, base|cmd, msk, value }, */\
+       {0xFFFF, PWR_CUT_ALL_MSK, PWR_FAB_ALL_MSK, PWR_INTF_ALL_MSK,    \
+       0, PWR_CMD_END, 0, 0}
+
+extern struct
+wlan_pwr_cfg rtl8723A_power_on_flow[RTL8723A_TRANS_CARDEMU_TO_ACT_STPS
+                                   + RTL8723A_TRANS_END_STPS];
+extern struct
+wlan_pwr_cfg rtl8723A_radio_off_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                    + RTL8723A_TRANS_END_STPS];
+extern struct
+wlan_pwr_cfg rtl8723A_card_disable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                       + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
+                                       + RTL8723A_TRANS_END_STPS];
+extern struct
+wlan_pwr_cfg rtl8723A_card_enable_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                      + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
+                                      + RTL8723A_TRANS_END_STPS];
+extern struct
+wlan_pwr_cfg rtl8723A_suspend_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                  + RTL8723A_TRANS_CARDEMU_TO_SUS_STPS
+                                  + RTL8723A_TRANS_END_STPS];
+extern struct
+wlan_pwr_cfg rtl8723A_resume_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                 + RTL8723A_TRANS_CARDEMU_TO_SUS_STPS
+                                 + RTL8723A_TRANS_END_STPS];
+extern struct
+wlan_pwr_cfg rtl8723A_hwpdn_flow[RTL8723A_TRANS_ACT_TO_CARDEMU_STPS
+                                + RTL8723A_TRANS_CARDEMU_TO_PDN_STPS
+                                + RTL8723A_TRANS_END_STPS];
+extern struct
+wlan_pwr_cfg rtl8723A_enter_lps_flow[RTL8723A_TRANS_ACT_TO_LPS_STPS
+                                    + RTL8723A_TRANS_END_STPS];
+extern struct
+wlan_pwr_cfg rtl8723A_leave_lps_flow[RTL8723A_TRANS_LPS_TO_ACT_STPS
+                                    + RTL8723A_TRANS_END_STPS];
+
+/* RTL8723 Power Configuration CMDs for PCIe interface */
+#define Rtl8723_NIC_PWR_ON_FLOW                rtl8723A_power_on_flow
+#define Rtl8723_NIC_RF_OFF_FLOW                rtl8723A_radio_off_flow
+#define Rtl8723_NIC_DISABLE_FLOW       rtl8723A_card_disable_flow
+#define Rtl8723_NIC_ENABLE_FLOW                rtl8723A_card_enable_flow
+#define Rtl8723_NIC_SUSPEND_FLOW       rtl8723A_suspend_flow
+#define Rtl8723_NIC_RESUME_FLOW                rtl8723A_resume_flow
+#define Rtl8723_NIC_PDN_FLOW           rtl8723A_hwpdn_flow
+#define Rtl8723_NIC_LPS_ENTER_FLOW     rtl8723A_enter_lps_flow
+#define Rtl8723_NIC_LPS_LEAVE_FLOW     rtl8723A_leave_lps_flow
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.c b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.c
new file mode 100644 (file)
index 0000000..2044b59
--- /dev/null
@@ -0,0 +1,129 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "pwrseq.h"
+
+/*     Description:
+ *             This routine deals with the Power Configuration CMD
+ *              parsing for RTL8723/RTL8188E Series IC.
+ *     Assumption:
+ *             We should follow specific format that was released from HW SD.
+ */
+bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+                             u8 faversion, u8 interface_type,
+                             struct wlan_pwr_cfg pwrcfgcmd[])
+{
+       struct wlan_pwr_cfg cfg_cmd = {0};
+       bool polling_bit = false;
+       u32 ary_idx = 0;
+       u8 value = 0;
+       u32 offset = 0;
+       u32 polling_count = 0;
+       u32 max_polling_cnt = 5000;
+
+       do {
+               cfg_cmd = pwrcfgcmd[ary_idx];
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                       "rtl_hal_pwrseqcmdparsing(): offset(%#x),cut_msk(%#x), famsk(%#x),"
+                       "interface_msk(%#x), base(%#x), cmd(%#x), msk(%#x), value(%#x)\n",
+                       GET_PWR_CFG_OFFSET(cfg_cmd),
+                                          GET_PWR_CFG_CUT_MASK(cfg_cmd),
+                       GET_PWR_CFG_FAB_MASK(cfg_cmd),
+                                            GET_PWR_CFG_INTF_MASK(cfg_cmd),
+                       GET_PWR_CFG_BASE(cfg_cmd), GET_PWR_CFG_CMD(cfg_cmd),
+                       GET_PWR_CFG_MASK(cfg_cmd), GET_PWR_CFG_VALUE(cfg_cmd));
+
+               if ((GET_PWR_CFG_FAB_MASK(cfg_cmd)&faversion) &&
+                   (GET_PWR_CFG_CUT_MASK(cfg_cmd)&cut_version) &&
+                   (GET_PWR_CFG_INTF_MASK(cfg_cmd)&interface_type)) {
+                       switch (GET_PWR_CFG_CMD(cfg_cmd)) {
+                       case PWR_CMD_READ:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                       "rtl_hal_pwrseqcmdparsing(): PWR_CMD_READ\n");
+                               break;
+                       case PWR_CMD_WRITE:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                       "rtl_hal_pwrseqcmdparsing(): PWR_CMD_WRITE\n");
+                               offset = GET_PWR_CFG_OFFSET(cfg_cmd);
+
+                               /*Read the value from system register*/
+                               value = rtl_read_byte(rtlpriv, offset);
+                               value &= (~(GET_PWR_CFG_MASK(cfg_cmd)));
+                               value |= (GET_PWR_CFG_VALUE(cfg_cmd) &
+                                         GET_PWR_CFG_MASK(cfg_cmd));
+
+                               /*Write the value back to sytem register*/
+                               rtl_write_byte(rtlpriv, offset, value);
+                               break;
+                       case PWR_CMD_POLLING:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                       "rtl_hal_pwrseqcmdparsing(): PWR_CMD_POLLING\n");
+                               polling_bit = false;
+                               offset = GET_PWR_CFG_OFFSET(cfg_cmd);
+
+                               do {
+                                       value = rtl_read_byte(rtlpriv, offset);
+
+                                       value &= GET_PWR_CFG_MASK(cfg_cmd);
+                                       if (value ==
+                                           (GET_PWR_CFG_VALUE(cfg_cmd)
+                                           & GET_PWR_CFG_MASK(cfg_cmd)))
+                                               polling_bit = true;
+                                       else
+                                               udelay(10);
+
+                                       if (polling_count++ > max_polling_cnt)
+                                               return false;
+                               } while (!polling_bit);
+                               break;
+                       case PWR_CMD_DELAY:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                       "rtl_hal_pwrseqcmdparsing(): PWR_CMD_DELAY\n");
+                               if (GET_PWR_CFG_VALUE(cfg_cmd) ==
+                                   PWRSEQ_DELAY_US)
+                                       udelay(GET_PWR_CFG_OFFSET(cfg_cmd));
+                               else
+                                       mdelay(GET_PWR_CFG_OFFSET(cfg_cmd));
+                               break;
+                       case PWR_CMD_END:
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                        "rtl_hal_pwrseqcmdparsing(): PWR_CMD_END\n");
+                               return true;
+                       default:
+                               RT_ASSERT(false,
+                                        "rtl_hal_pwrseqcmdparsing(): Unknown CMD!!\n");
+                               break;
+                       }
+
+               }
+               ary_idx++;
+       } while (1);
+
+       return true;
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.h b/drivers/net/wireless/rtlwifi/rtl8723ae/pwrseqcmd.h
new file mode 100644 (file)
index 0000000..6e0f3ea
--- /dev/null
@@ -0,0 +1,98 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_PWRSEQCMD_H__
+#define __RTL8723E_PWRSEQCMD_H__
+
+#include "../wifi.h"
+/*---------------------------------------------
+ * 3 The value of cmd: 4 bits
+ *---------------------------------------------
+ */
+#define    PWR_CMD_READ                0x00
+#define    PWR_CMD_WRITE       0x01
+#define    PWR_CMD_POLLING     0x02
+#define    PWR_CMD_DELAY       0x03
+#define    PWR_CMD_END         0x04
+
+/* define the base address of each block */
+#define   PWR_BASEADDR_MAC     0x00
+#define   PWR_BASEADDR_USB     0x01
+#define   PWR_BASEADDR_PCIE    0x02
+#define   PWR_BASEADDR_SDIO    0x03
+
+#define        PWR_INTF_SDIO_MSK       BIT(0)
+#define        PWR_INTF_USB_MSK        BIT(1)
+#define        PWR_INTF_PCI_MSK        BIT(2)
+#define        PWR_INTF_ALL_MSK        (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+#define        PWR_FAB_TSMC_MSK        BIT(0)
+#define        PWR_FAB_UMC_MSK         BIT(1)
+#define        PWR_FAB_ALL_MSK         (BIT(0)|BIT(1)|BIT(2)|BIT(3))
+
+#define        PWR_CUT_TESTCHIP_MSK    BIT(0)
+#define        PWR_CUT_A_MSK           BIT(1)
+#define        PWR_CUT_B_MSK           BIT(2)
+#define        PWR_CUT_C_MSK           BIT(3)
+#define        PWR_CUT_D_MSK           BIT(4)
+#define        PWR_CUT_E_MSK           BIT(5)
+#define        PWR_CUT_F_MSK           BIT(6)
+#define        PWR_CUT_G_MSK           BIT(7)
+#define        PWR_CUT_ALL_MSK         0xFF
+
+enum pwrseq_delay_unit {
+       PWRSEQ_DELAY_US,
+       PWRSEQ_DELAY_MS,
+};
+
+struct wlan_pwr_cfg {
+       u16 offset;
+       u8 cut_msk;
+       u8 fab_msk:4;
+       u8 interface_msk:4;
+       u8 base:4;
+       u8 cmd:4;
+       u8 msk;
+       u8 value;
+};
+
+#define        GET_PWR_CFG_OFFSET(__PWR_CMD)   (__PWR_CMD.offset)
+#define        GET_PWR_CFG_CUT_MASK(__PWR_CMD) (__PWR_CMD.cut_msk)
+#define        GET_PWR_CFG_FAB_MASK(__PWR_CMD) (__PWR_CMD.fab_msk)
+#define        GET_PWR_CFG_INTF_MASK(__PWR_CMD)        (__PWR_CMD.interface_msk)
+#define        GET_PWR_CFG_BASE(__PWR_CMD)     (__PWR_CMD.base)
+#define        GET_PWR_CFG_CMD(__PWR_CMD)      (__PWR_CMD.cmd)
+#define        GET_PWR_CFG_MASK(__PWR_CMD)     (__PWR_CMD.msk)
+#define        GET_PWR_CFG_VALUE(__PWR_CMD)    (__PWR_CMD.value)
+
+bool rtl_hal_pwrseqcmdparsing(struct rtl_priv *rtlpriv, u8 cut_version,
+                             u8 fab_version, u8 interface_type,
+                             struct wlan_pwr_cfg pwrcfgcmd[]);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h b/drivers/net/wireless/rtlwifi/rtl8723ae/reg.h
new file mode 100644 (file)
index 0000000..199da36
--- /dev/null
@@ -0,0 +1,2097 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_REG_H__
+#define __RTL8723E_REG_H__
+
+#define REG_SYS_ISO_CTRL                       0x0000
+#define REG_SYS_FUNC_EN                                0x0002
+#define REG_APS_FSMCO                          0x0004
+#define REG_SYS_CLKR                           0x0008
+#define REG_9346CR                             0x000A
+#define REG_EE_VPD                             0x000C
+#define REG_AFE_MISC                           0x0010
+#define REG_SPS0_CTRL                          0x0011
+#define REG_SPS_OCP_CFG                                0x0018
+#define REG_RSV_CTRL                           0x001C
+#define REG_RF_CTRL                            0x001F
+#define REG_LDOA15_CTRL                                0x0020
+#define REG_LDOV12D_CTRL                       0x0021
+#define REG_LDOHCI12_CTRL                      0x0022
+#define REG_LPLDO_CTRL                         0x0023
+#define REG_AFE_XTAL_CTRL                      0x0024
+#define REG_AFE_PLL_CTRL                       0x0028
+#define REG_EFUSE_CTRL                         0x0030
+#define REG_EFUSE_TEST                         0x0034
+#define REG_PWR_DATA                           0x0038
+#define REG_CAL_TIMER                          0x003C
+#define REG_ACLK_MON                           0x003E
+#define REG_GPIO_MUXCFG                                0x0040
+#define REG_GPIO_IO_SEL                                0x0042
+#define REG_MAC_PINMUX_CFG                     0x0043
+#define REG_GPIO_PIN_CTRL                      0x0044
+#define REG_GPIO_INTM                          0x0048
+#define REG_LEDCFG0                            0x004C
+#define REG_LEDCFG1                            0x004D
+#define REG_LEDCFG2                            0x004E
+#define REG_LEDCFG3                            0x004F
+#define REG_FSIMR                              0x0050
+#define REG_FSISR                              0x0054
+#define REG_GPIO_PIN_CTRL_2                    0x0060
+#define REG_GPIO_IO_SEL_2                      0x0062
+#define REG_MULTI_FUNC_CTRL                    0x0068
+
+#define REG_MCUFWDL                            0x0080
+
+#define REG_HMEBOX_EXT_0                       0x0088
+#define REG_HMEBOX_EXT_1                       0x008A
+#define REG_HMEBOX_EXT_2                       0x008C
+#define REG_HMEBOX_EXT_3                       0x008E
+
+#define REG_BIST_SCAN                          0x00D0
+#define REG_BIST_RPT                           0x00D4
+#define REG_BIST_ROM_RPT                       0x00D8
+#define REG_USB_SIE_INTF                       0x00E0
+#define REG_PCIE_MIO_INTF                      0x00E4
+#define REG_PCIE_MIO_INTD                      0x00E8
+#define REG_SYS_CFG                            0x00F0
+#define REG_GPIO_OUTSTS                                0x00F4
+
+#define REG_CR                                 0x0100
+#define REG_PBP                                        0x0104
+#define REG_TRXDMA_CTRL                                0x010C
+#define REG_TRXFF_BNDY                         0x0114
+#define REG_TRXFF_STATUS                       0x0118
+#define REG_RXFF_PTR                           0x011C
+#define REG_HIMR                               0x0120
+#define REG_HISR                               0x0124
+#define REG_HIMRE                              0x0128
+#define REG_HISRE                              0x012C
+#define REG_CPWM                               0x012F
+#define REG_FWIMR                              0x0130
+#define REG_FWISR                              0x0134
+#define REG_PKTBUF_DBG_CTRL                    0x0140
+#define REG_PKTBUF_DBG_DATA_L                  0x0144
+#define REG_PKTBUF_DBG_DATA_H                  0x0148
+
+#define REG_TC0_CTRL                           0x0150
+#define REG_TC1_CTRL                           0x0154
+#define REG_TC2_CTRL                           0x0158
+#define REG_TC3_CTRL                           0x015C
+#define REG_TC4_CTRL                           0x0160
+#define REG_TCUNIT_BASE                                0x0164
+#define REG_MBIST_START                                0x0174
+#define REG_MBIST_DONE                         0x0178
+#define REG_MBIST_FAIL                         0x017C
+#define REG_C2HEVT_MSG_NORMAL                  0x01A0
+#define REG_C2HEVT_MSG_TEST                    0x01B8
+#define REG_MCUTST_1                           0x01c0
+#define REG_FMETHR                             0x01C8
+#define REG_HMETFR                             0x01CC
+#define REG_HMEBOX_0                           0x01D0
+#define REG_HMEBOX_1                           0x01D4
+#define REG_HMEBOX_2                           0x01D8
+#define REG_HMEBOX_3                           0x01DC
+
+#define REG_LLT_INIT                           0x01E0
+#define REG_BB_ACCEESS_CTRL                    0x01E8
+#define REG_BB_ACCESS_DATA                     0x01EC
+
+#define REG_RQPN                               0x0200
+#define REG_FIFOPAGE                           0x0204
+#define REG_TDECTRL                            0x0208
+#define REG_TXDMA_OFFSET_CHK                   0x020C
+#define REG_TXDMA_STATUS                       0x0210
+#define REG_RQPN_NPQ                           0x0214
+
+#define REG_RXDMA_AGG_PG_TH                    0x0280
+#define REG_RXPKT_NUM                          0x0284
+#define REG_RXDMA_STATUS                       0x0288
+
+#define        REG_PCIE_CTRL_REG                       0x0300
+#define        REG_INT_MIG                             0x0304
+#define        REG_BCNQ_DESA                           0x0308
+#define        REG_HQ_DESA                             0x0310
+#define        REG_MGQ_DESA                            0x0318
+#define        REG_VOQ_DESA                            0x0320
+#define        REG_VIQ_DESA                            0x0328
+#define        REG_BEQ_DESA                            0x0330
+#define        REG_BKQ_DESA                            0x0338
+#define        REG_RX_DESA                             0x0340
+#define        REG_DBI                                 0x0348
+#define        REG_MDIO                                0x0354
+#define        REG_DBG_SEL                             0x0360
+#define        REG_PCIE_HRPWM                          0x0361
+#define        REG_PCIE_HCPWM                          0x0363
+#define        REG_UART_CTRL                           0x0364
+#define        REG_UART_TX_DESA                        0x0370
+#define        REG_UART_RX_DESA                        0x0378
+
+#define        REG_HDAQ_DESA_NODEF                     0x0000
+#define        REG_CMDQ_DESA_NODEF                     0x0000
+
+#define REG_VOQ_INFORMATION                    0x0400
+#define REG_VIQ_INFORMATION                    0x0404
+#define REG_BEQ_INFORMATION                    0x0408
+#define REG_BKQ_INFORMATION                    0x040C
+#define REG_MGQ_INFORMATION                    0x0410
+#define REG_HGQ_INFORMATION                    0x0414
+#define REG_BCNQ_INFORMATION                   0x0418
+
+#define REG_CPU_MGQ_INFORMATION                        0x041C
+#define REG_FWHW_TXQ_CTRL                      0x0420
+#define REG_HWSEQ_CTRL                         0x0423
+#define REG_TXPKTBUF_BCNQ_BDNY                 0x0424
+#define REG_TXPKTBUF_MGQ_BDNY                  0x0425
+#define REG_MULTI_BCNQ_EN                      0x0426
+#define REG_MULTI_BCNQ_OFFSET                  0x0427
+#define REG_SPEC_SIFS                          0x0428
+#define REG_RL                                 0x042A
+#define REG_DARFRC                             0x0430
+#define REG_RARFRC                             0x0438
+#define REG_RRSR                               0x0440
+#define REG_ARFR0                              0x0444
+#define REG_ARFR1                              0x0448
+#define REG_ARFR2                              0x044C
+#define REG_ARFR3                              0x0450
+#define REG_AGGLEN_LMT                         0x0458
+#define REG_AMPDU_MIN_SPACE                    0x045C
+#define REG_TXPKTBUF_WMAC_LBK_BF_HD            0x045D
+#define REG_FAST_EDCA_CTRL                     0x0460
+#define REG_RD_RESP_PKT_TH                     0x0463
+#define REG_INIRTS_RATE_SEL                    0x0480
+#define REG_INIDATA_RATE_SEL                   0x0484
+#define REG_POWER_STATUS                       0x04A4
+#define REG_POWER_STAGE1                       0x04B4
+#define REG_POWER_STAGE2                       0x04B8
+#define REG_PKT_LIFE_TIME                      0x04C0
+#define REG_STBC_SETTING                       0x04C4
+#define REG_PROT_MODE_CTRL                     0x04C8
+#define REG_BAR_MODE_CTRL                      0x04CC
+#define REG_RA_TRY_RATE_AGG_LMT                        0x04CF
+#define REG_NQOS_SEQ                           0x04DC
+#define REG_QOS_SEQ                            0x04DE
+#define REG_NEED_CPU_HANDLE                    0x04E0
+#define REG_PKT_LOSE_RPT                       0x04E1
+#define REG_PTCL_ERR_STATUS                    0x04E2
+#define REG_DUMMY                              0x04FC
+
+#define REG_EDCA_VO_PARAM                      0x0500
+#define REG_EDCA_VI_PARAM                      0x0504
+#define REG_EDCA_BE_PARAM                      0x0508
+#define REG_EDCA_BK_PARAM                      0x050C
+#define REG_BCNTCFG                            0x0510
+#define REG_PIFS                               0x0512
+#define REG_RDG_PIFS                           0x0513
+#define REG_SIFS_CTX                           0x0514
+#define REG_SIFS_TRX                           0x0516
+#define REG_AGGR_BREAK_TIME                    0x051A
+#define REG_SLOT                               0x051B
+#define REG_TX_PTCL_CTRL                       0x0520
+#define REG_TXPAUSE                            0x0522
+#define REG_DIS_TXREQ_CLR                      0x0523
+#define REG_RD_CTRL                            0x0524
+#define REG_TBTT_PROHIBIT                      0x0540
+#define REG_RD_NAV_NXT                         0x0544
+#define REG_NAV_PROT_LEN                       0x0546
+#define REG_BCN_CTRL                           0x0550
+#define REG_USTIME_TSF                         0x0551
+#define REG_MBID_NUM                           0x0552
+#define REG_DUAL_TSF_RST                       0x0553
+#define REG_BCN_INTERVAL                       0x0554
+#define REG_MBSSID_BCN_SPACE                   0x0554
+#define REG_DRVERLYINT                         0x0558
+#define REG_BCNDMATIM                          0x0559
+#define REG_ATIMWND                            0x055A
+#define REG_BCN_MAX_ERR                                0x055D
+#define REG_RXTSF_OFFSET_CCK                   0x055E
+#define REG_RXTSF_OFFSET_OFDM                  0x055F
+#define REG_TSFTR                              0x0560
+#define REG_INIT_TSFTR                         0x0564
+#define REG_PSTIMER                            0x0580
+#define REG_TIMER0                             0x0584
+#define REG_TIMER1                             0x0588
+#define REG_ACMHWCTRL                          0x05C0
+#define REG_ACMRSTCTRL                         0x05C1
+#define REG_ACMAVG                             0x05C2
+#define REG_VO_ADMTIME                         0x05C4
+#define REG_VI_ADMTIME                         0x05C6
+#define REG_BE_ADMTIME                         0x05C8
+#define REG_EDCA_RANDOM_GEN                    0x05CC
+#define REG_SCH_TXCMD                          0x05D0
+
+#define REG_APSD_CTRL                          0x0600
+#define REG_BWOPMODE                           0x0603
+#define REG_TCR                                        0x0604
+#define REG_RCR                                        0x0608
+#define REG_RX_PKT_LIMIT                       0x060C
+#define REG_RX_DLK_TIME                                0x060D
+#define REG_RX_DRVINFO_SZ                      0x060F
+
+#define REG_MACID                              0x0610
+#define REG_BSSID                              0x0618
+#define REG_MAR                                        0x0620
+#define REG_MBIDCAMCFG                         0x0628
+
+#define REG_USTIME_EDCA                                0x0638
+#define REG_MAC_SPEC_SIFS                      0x063A
+#define REG_RESP_SIFS_CCK                      0x063C
+#define REG_RESP_SIFS_OFDM                     0x063E
+#define REG_ACKTO                              0x0640
+#define REG_CTS2TO                             0x0641
+#define REG_EIFS                               0x0642
+
+#define REG_NAV_CTRL                           0x0650
+#define REG_BACAMCMD                           0x0654
+#define REG_BACAMCONTENT                       0x0658
+#define REG_LBDLY                              0x0660
+#define REG_FWDLY                              0x0661
+#define REG_RXERR_RPT                          0x0664
+#define REG_WMAC_TRXPTCL_CTL                   0x0668
+
+#define REG_CAMCMD                             0x0670
+#define REG_CAMWRITE                           0x0674
+#define REG_CAMREAD                            0x0678
+#define REG_CAMDBG                             0x067C
+#define REG_SECCFG                             0x0680
+
+#define REG_WOW_CTRL                           0x0690
+#define REG_PSSTATUS                           0x0691
+#define REG_PS_RX_INFO                         0x0692
+#define REG_LPNAV_CTRL                         0x0694
+#define REG_WKFMCAM_CMD                                0x0698
+#define REG_WKFMCAM_RWD                                0x069C
+#define REG_RXFLTMAP0                          0x06A0
+#define REG_RXFLTMAP1                          0x06A2
+#define REG_RXFLTMAP2                          0x06A4
+#define REG_BCN_PSR_RPT                                0x06A8
+#define REG_CALB32K_CTRL                       0x06AC
+#define REG_PKT_MON_CTRL                       0x06B4
+#define REG_BT_COEX_TABLE                      0x06C0
+#define REG_WMAC_RESP_TXINFO                   0x06D8
+
+#define REG_USB_INFO                           0xFE17
+#define REG_USB_SPECIAL_OPTION                 0xFE55
+#define REG_USB_DMA_AGG_TO                     0xFE5B
+#define REG_USB_AGG_TO                         0xFE5C
+#define REG_USB_AGG_TH                         0xFE5D
+
+#define REG_TEST_USB_TXQS                      0xFE48
+#define REG_TEST_SIE_VID                       0xFE60
+#define REG_TEST_SIE_PID                       0xFE62
+#define REG_TEST_SIE_OPTIONAL                  0xFE64
+#define REG_TEST_SIE_CHIRP_K                   0xFE65
+#define REG_TEST_SIE_PHY                       0xFE66
+#define REG_TEST_SIE_MAC_ADDR                  0xFE70
+#define REG_TEST_SIE_STRING                    0xFE80
+
+#define REG_NORMAL_SIE_VID                     0xFE60
+#define REG_NORMAL_SIE_PID                     0xFE62
+#define REG_NORMAL_SIE_OPTIONAL                        0xFE64
+#define REG_NORMAL_SIE_EP                      0xFE65
+#define REG_NORMAL_SIE_PHY                     0xFE68
+#define REG_NORMAL_SIE_MAC_ADDR                        0xFE70
+#define REG_NORMAL_SIE_STRING                  0xFE80
+
+#define        CR9346                                  REG_9346CR
+#define        MSR                                     (REG_CR + 2)
+#define        ISR                                     REG_HISR
+#define        TSFR                                    REG_TSFTR
+
+#define        MACIDR0                                 REG_MACID
+#define        MACIDR4                                 (REG_MACID + 4)
+
+#define PBP                                    REG_PBP
+
+#define        IDR0                                    MACIDR0
+#define        IDR4                                    MACIDR4
+
+#define        UNUSED_REGISTER                         0x1BF
+#define        DCAM                                    UNUSED_REGISTER
+#define        PSR                                     UNUSED_REGISTER
+#define BBADDR                                 UNUSED_REGISTER
+#define        PHYDATAR                                UNUSED_REGISTER
+
+#define        INVALID_BBRF_VALUE                      0x12345678
+
+#define        MAX_MSS_DENSITY_2T                      0x13
+#define        MAX_MSS_DENSITY_1T                      0x0A
+
+#define        CMDEEPROM_EN                            BIT(5)
+#define        CMDEEPROM_SEL                           BIT(4)
+#define        CMD9346CR_9356SEL                       BIT(4)
+#define        AUTOLOAD_EEPROM                         (CMDEEPROM_EN|CMDEEPROM_SEL)
+#define        AUTOLOAD_EFUSE                          CMDEEPROM_EN
+
+#define        GPIOSEL_GPIO                            0
+#define        GPIOSEL_ENBT                            BIT(5)
+
+#define        GPIO_IN                                 REG_GPIO_PIN_CTRL
+#define        GPIO_OUT                                (REG_GPIO_PIN_CTRL+1)
+#define        GPIO_IO_SEL                             (REG_GPIO_PIN_CTRL+2)
+#define        GPIO_MOD                                (REG_GPIO_PIN_CTRL+3)
+
+#define        MSR_NOLINK                              0x00
+#define        MSR_ADHOC                               0x01
+#define        MSR_INFRA                               0x02
+#define        MSR_AP                                  0x03
+
+#define        RRSR_RSC_OFFSET                         21
+#define        RRSR_SHORT_OFFSET                       23
+#define        RRSR_RSC_BW_40M                         0x600000
+#define        RRSR_RSC_UPSUBCHNL                      0x400000
+#define        RRSR_RSC_LOWSUBCHNL                     0x200000
+#define        RRSR_SHORT                              0x800000
+#define        RRSR_1M                                 BIT(0)
+#define        RRSR_2M                                 BIT(1)
+#define        RRSR_5_5M                               BIT(2)
+#define        RRSR_11M                                BIT(3)
+#define        RRSR_6M                                 BIT(4)
+#define        RRSR_9M                                 BIT(5)
+#define        RRSR_12M                                BIT(6)
+#define        RRSR_18M                                BIT(7)
+#define        RRSR_24M                                BIT(8)
+#define        RRSR_36M                                BIT(9)
+#define        RRSR_48M                                BIT(10)
+#define        RRSR_54M                                BIT(11)
+#define        RRSR_MCS0                               BIT(12)
+#define        RRSR_MCS1                               BIT(13)
+#define        RRSR_MCS2                               BIT(14)
+#define        RRSR_MCS3                               BIT(15)
+#define        RRSR_MCS4                               BIT(16)
+#define        RRSR_MCS5                               BIT(17)
+#define        RRSR_MCS6                               BIT(18)
+#define        RRSR_MCS7                               BIT(19)
+#define        BRSR_ACKSHORTPMB                        BIT(23)
+
+#define        RATR_1M                                 0x00000001
+#define        RATR_2M                                 0x00000002
+#define        RATR_55M                                0x00000004
+#define        RATR_11M                                0x00000008
+#define        RATR_6M                                 0x00000010
+#define        RATR_9M                                 0x00000020
+#define        RATR_12M                                0x00000040
+#define        RATR_18M                                0x00000080
+#define        RATR_24M                                0x00000100
+#define        RATR_36M                                0x00000200
+#define        RATR_48M                                0x00000400
+#define        RATR_54M                                0x00000800
+#define        RATR_MCS0                               0x00001000
+#define        RATR_MCS1                               0x00002000
+#define        RATR_MCS2                               0x00004000
+#define        RATR_MCS3                               0x00008000
+#define        RATR_MCS4                               0x00010000
+#define        RATR_MCS5                               0x00020000
+#define        RATR_MCS6                               0x00040000
+#define        RATR_MCS7                               0x00080000
+#define        RATR_MCS8                               0x00100000
+#define        RATR_MCS9                               0x00200000
+#define        RATR_MCS10                              0x00400000
+#define        RATR_MCS11                              0x00800000
+#define        RATR_MCS12                              0x01000000
+#define        RATR_MCS13                              0x02000000
+#define        RATR_MCS14                              0x04000000
+#define        RATR_MCS15                              0x08000000
+
+#define        RATE_ALL_CCK            (RATR_1M | RATR_2M | RATR_55M | RATR_11M)
+#define        RATE_ALL_OFDM_AG        (RATR_6M | RATR_9M | RATR_12M | RATR_18M |\
+                               RATR_24M | RATR_36M | RATR_48M | RATR_54M)
+#define        RATE_ALL_OFDM_1SS       (RATR_MCS0 | RATR_MCS1 | RATR_MCS2 |\
+                               RATR_MCS3 | RATR_MCS4 | RATR_MCS5 |\
+                               RATR_MCS6 | RATR_MCS7)
+#define        RATE_ALL_OFDM_2SS       (RATR_MCS8 | RATR_MCS9 | RATR_MCS10 |\
+                               RATR_MCS11 | RATR_MCS12 | RATR_MCS13 |\
+                               RATR_MCS14 | RATR_MCS15)
+
+#define        BW_OPMODE_20MHZ                         BIT(2)
+#define        BW_OPMODE_5G                            BIT(1)
+#define        BW_OPMODE_11J                           BIT(0)
+
+#define        CAM_VALID                               BIT(15)
+#define        CAM_NOTVALID                            0x0000
+#define        CAM_USEDK                               BIT(5)
+
+#define        CAM_NONE                                0x0
+#define        CAM_WEP40                               0x01
+#define        CAM_TKIP                                0x02
+#define        CAM_AES                                 0x04
+#define        CAM_WEP104                              0x05
+
+#define        TOTAL_CAM_ENTRY                         32
+#define        HALF_CAM_ENTRY                          16
+
+#define        CAM_WRITE                               BIT(16)
+#define        CAM_READ                                0x00000000
+#define        CAM_POLLINIG                            BIT(31)
+
+#define        SCR_USEDK                               0x01
+#define        SCR_TXSEC_ENABLE                        0x02
+#define        SCR_RXSEC_ENABLE                        0x04
+
+#define        WOW_PMEN                                BIT(0)
+#define        WOW_WOMEN                               BIT(1)
+#define        WOW_MAGIC                               BIT(2)
+#define        WOW_UWF                                 BIT(3)
+
+#define        IMR8190_DISABLED                        0x0
+#define        IMR_BCNDMAINT6                          BIT(31)
+#define        IMR_BCNDMAINT5                          BIT(30)
+#define        IMR_BCNDMAINT4                          BIT(29)
+#define        IMR_BCNDMAINT3                          BIT(28)
+#define        IMR_BCNDMAINT2                          BIT(27)
+#define        IMR_BCNDMAINT1                          BIT(26)
+#define        IMR_BCNDOK8                             BIT(25)
+#define        IMR_BCNDOK7                             BIT(24)
+#define        IMR_BCNDOK6                             BIT(23)
+#define        IMR_BCNDOK5                             BIT(22)
+#define        IMR_BCNDOK4                             BIT(21)
+#define        IMR_BCNDOK3                             BIT(20)
+#define        IMR_BCNDOK2                             BIT(19)
+#define        IMR_BCNDOK1                             BIT(18)
+#define        IMR_TIMEOUT2                            BIT(17)
+#define        IMR_TIMEOUT1                            BIT(16)
+#define        IMR_TXFOVW                              BIT(15)
+#define        IMR_PSTIMEOUT                           BIT(14)
+#define        IMR_BCNINT                              BIT(13)
+#define        IMR_RXFOVW                              BIT(12)
+#define        IMR_RDU                                 BIT(11)
+#define        IMR_ATIMEND                             BIT(10)
+#define        IMR_BDOK                                BIT(9)
+#define        IMR_HIGHDOK                             BIT(8)
+#define        IMR_TBDOK                               BIT(7)
+#define        IMR_MGNTDOK                             BIT(6)
+#define        IMR_TBDER                               BIT(5)
+#define        IMR_BKDOK                               BIT(4)
+#define        IMR_BEDOK                               BIT(3)
+#define        IMR_VIDOK                               BIT(2)
+#define        IMR_VODOK                               BIT(1)
+#define        IMR_ROK                                 BIT(0)
+
+#define        IMR_TXERR                               BIT(11)
+#define        IMR_RXERR                               BIT(10)
+#define        IMR_CPWM                                BIT(8)
+#define        IMR_OCPINT                              BIT(1)
+#define        IMR_WLANOFF                             BIT(0)
+
+/* 8723E series PCIE Host IMR/ISR bit */
+/* IMR DW0 Bit 0-31 */
+#define        PHIMR_TIMEOUT2                          BIT(31)
+#define        PHIMR_TIMEOUT1                          BIT(30)
+#define        PHIMR_PSTIMEOUT                         BIT(29)
+#define        PHIMR_GTINT4                            BIT(28)
+#define        PHIMR_GTINT3                            BIT(27)
+#define        PHIMR_TXBCNERR                          BIT(26)
+#define        PHIMR_TXBCNOK                           BIT(25)
+#define        PHIMR_TSF_BIT32_TOGGLE                  BIT(24)
+#define        PHIMR_BCNDMAINT3                        BIT(23)
+#define        PHIMR_BCNDMAINT2                        BIT(22)
+#define        PHIMR_BCNDMAINT1                        BIT(21)
+#define        PHIMR_BCNDMAINT0                        BIT(20)
+#define        PHIMR_BCNDOK3                           BIT(19)
+#define        PHIMR_BCNDOK2                           BIT(18)
+#define        PHIMR_BCNDOK1                           BIT(17)
+#define        PHIMR_BCNDOK0                           BIT(16)
+#define        PHIMR_HSISR_IND_ON                      BIT(15)
+#define        PHIMR_BCNDMAINT_E                       BIT(14)
+#define        PHIMR_ATIMEND_E                         BIT(13)
+#define        PHIMR_ATIM_CTW_END                      BIT(12)
+#define        PHIMR_HISRE_IND                         BIT(11)
+#define        PHIMR_C2HCMD                            BIT(10)
+#define        PHIMR_CPWM2                             BIT(9)
+#define        PHIMR_CPWM                              BIT(8)
+#define        PHIMR_HIGHDOK                           BIT(7)
+#define        PHIMR_MGNTDOK                           BIT(6)
+#define        PHIMR_BKDOK                             BIT(5)
+#define        PHIMR_BEDOK                             BIT(4)
+#define        PHIMR_VIDOK                             BIT(3)
+#define        PHIMR_VODOK                             BIT(2)
+#define        PHIMR_RDU                               BIT(1)
+#define        PHIMR_ROK                               BIT(0)
+
+/* PCIE Host Interrupt Status Extension bit */
+#define        PHIMR_BCNDMAINT7                        BIT(23)
+#define        PHIMR_BCNDMAINT6                        BIT(22)
+#define        PHIMR_BCNDMAINT5                        BIT(21)
+#define        PHIMR_BCNDMAINT4                        BIT(20)
+#define        PHIMR_BCNDOK7                           BIT(19)
+#define        PHIMR_BCNDOK6                           BIT(18)
+#define        PHIMR_BCNDOK5                           BIT(17)
+#define        PHIMR_BCNDOK4                           BIT(16)
+/* bit12-15: RSVD */
+#define        PHIMR_TXERR                             BIT(11)
+#define        PHIMR_RXERR                             BIT(10)
+#define        PHIMR_TXFOVW                            BIT(9)
+#define        PHIMR_RXFOVW                            BIT(8)
+/* bit2-7: RSV */
+#define        PHIMR_OCPINT                            BIT(1)
+
+#define        HWSET_MAX_SIZE                          256
+#define EFUSE_MAX_SECTION                      32
+#define EFUSE_REAL_CONTENT_LEN                 512
+#define EFUSE_OOB_PROTECT_BYTES                        15
+
+#define        EEPROM_DEFAULT_TSSI                     0x0
+#define EEPROM_DEFAULT_TXPOWERDIFF             0x0
+#define EEPROM_DEFAULT_CRYSTALCAP              0x5
+#define EEPROM_DEFAULT_BOARDTYPE               0x02
+#define EEPROM_DEFAULT_TXPOWER                 0x1010
+#define        EEPROM_DEFAULT_HT2T_TXPWR               0x10
+
+#define        EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF      0x3
+#define        EEPROM_DEFAULT_THERMALMETER             0x12
+#define        EEPROM_DEFAULT_ANTTXPOWERDIFF           0x0
+#define        EEPROM_DEFAULT_TXPWDIFF_CRYSTALCAP      0x5
+#define        EEPROM_DEFAULT_TXPOWERLEVEL             0x22
+#define        EEPROM_DEFAULT_HT40_2SDIFF              0x0
+#define EEPROM_DEFAULT_HT20_DIFF               2
+#define        EEPROM_DEFAULT_LEGACYHTTXPOWERDIFF      0x3
+#define EEPROM_DEFAULT_HT40_PWRMAXOFFSET       0
+#define EEPROM_DEFAULT_HT20_PWRMAXOFFSET       0
+
+
+#define EEPROM_DEFAULT_PID                     0x1234
+#define EEPROM_DEFAULT_VID                     0x5678
+#define EEPROM_DEFAULT_CUSTOMERID              0xAB
+#define EEPROM_DEFAULT_SUBCUSTOMERID           0xCD
+#define EEPROM_DEFAULT_VERSION                 0
+
+#define        EEPROM_CHANNEL_PLAN_FCC                 0x0
+#define        EEPROM_CHANNEL_PLAN_IC                  0x1
+#define        EEPROM_CHANNEL_PLAN_ETSI                0x2
+#define        EEPROM_CHANNEL_PLAN_SPAIN               0x3
+#define        EEPROM_CHANNEL_PLAN_FRANCE              0x4
+#define        EEPROM_CHANNEL_PLAN_MKK                 0x5
+#define        EEPROM_CHANNEL_PLAN_MKK1                0x6
+#define        EEPROM_CHANNEL_PLAN_ISRAEL              0x7
+#define        EEPROM_CHANNEL_PLAN_TELEC               0x8
+#define        EEPROM_CHANNEL_PLAN_GLOBAL_DOMAIN       0x9
+#define        EEPROM_CHANNEL_PLAN_WORLD_WIDE_13       0xA
+#define        EEPROM_CHANNEL_PLAN_NCC                 0xB
+#define        EEPROM_CHANNEL_PLAN_BY_HW_MASK          0x80
+
+#define EEPROM_CID_DEFAULT                     0x0
+#define EEPROM_CID_TOSHIBA                     0x4
+#define        EEPROM_CID_CCX                          0x10
+#define        EEPROM_CID_QMI                          0x0D
+#define EEPROM_CID_WHQL                                0xFE
+
+#define        RTL8192_EEPROM_ID                       0x8129
+
+#define RTL8190_EEPROM_ID                      0x8129
+#define EEPROM_HPON                            0x02
+#define EEPROM_CLK                             0x06
+#define EEPROM_TESTR                           0x08
+
+#define EEPROM_VID                             0x49
+#define EEPROM_DID                             0x4B
+#define EEPROM_SVID                            0x4D
+#define EEPROM_SMID                            0x4F
+
+#define EEPROM_MAC_ADDR                                0x67
+
+#define EEPROM_CCK_TX_PWR_INX                  0x5A
+#define EEPROM_HT40_1S_TX_PWR_INX              0x60
+#define EEPROM_HT40_2S_TX_PWR_INX_DIFF         0x66
+#define EEPROM_HT20_TX_PWR_INX_DIFF            0x69
+#define EEPROM_OFDM_TX_PWR_INX_DIFF            0x6C
+#define EEPROM_HT40_MAX_PWR_OFFSET             0x25
+#define EEPROM_HT20_MAX_PWR_OFFSET             0x22
+
+#define EEPROM_THERMAL_METER                   0x2a
+#define EEPROM_XTAL_K                          0x78
+#define EEPROM_RF_OPT1                         0x79
+#define EEPROM_RF_OPT2                         0x7A
+#define EEPROM_RF_OPT3                         0x7B
+#define EEPROM_RF_OPT4                         0x7C
+#define EEPROM_CHANNEL_PLAN                    0x28
+#define EEPROM_VERSION                         0x30
+#define EEPROM_CUSTOMER_ID                     0x31
+
+#define EEPROM_PWRDIFF                         0x54
+
+#define EEPROM_TXPOWERCCK                      0x10
+#define        EEPROM_TXPOWERHT40_1S                   0x16
+#define        EEPROM_TXPOWERHT40_2SDIFF               0x66
+#define EEPROM_TXPOWERHT20DIFF                 0x1C
+#define EEPROM_TXPOWER_OFDMDIFF                        0x1F
+
+#define        EEPROM_TXPWR_GROUP                      0x22
+
+#define EEPROM_TSSI_A                          0x29
+#define EEPROM_TSSI_B                          0x77
+
+#define EEPROM_CHANNELPLAN                     0x28
+
+#define RF_OPTION1                             0x2B
+#define RF_OPTION2                             0x2C
+#define RF_OPTION3                             0x2D
+#define RF_OPTION4                             0x2E
+
+#define        STOPBECON                               BIT(6)
+#define        STOPHIGHT                               BIT(5)
+#define        STOPMGT                                 BIT(4)
+#define        STOPVO                                  BIT(3)
+#define        STOPVI                                  BIT(2)
+#define        STOPBE                                  BIT(1)
+#define        STOPBK                                  BIT(0)
+
+#define        RCR_APPFCS                              BIT(31)
+#define        RCR_APP_MIC                             BIT(30)
+#define        RCR_APP_ICV                             BIT(29)
+#define        RCR_APP_PHYST_RXFF                      BIT(28)
+#define        RCR_APP_BA_SSN                          BIT(27)
+#define        RCR_ENMBID                              BIT(24)
+#define        RCR_LSIGEN                              BIT(23)
+#define        RCR_MFBEN                               BIT(22)
+#define        RCR_HTC_LOC_CTRL                        BIT(14)
+#define        RCR_AMF                                 BIT(13)
+#define        RCR_ACF                                 BIT(12)
+#define        RCR_ADF                                 BIT(11)
+#define        RCR_AICV                                BIT(9)
+#define        RCR_ACRC32                              BIT(8)
+#define        RCR_CBSSID_BCN                          BIT(7)
+#define        RCR_CBSSID_DATA                         BIT(6)
+#define        RCR_CBSSID                              RCR_CBSSID_DATA
+#define        RCR_APWRMGT                             BIT(5)
+#define        RCR_ADD3                                BIT(4)
+#define        RCR_AB                                  BIT(3)
+#define        RCR_AM                                  BIT(2)
+#define        RCR_APM                                 BIT(1)
+#define        RCR_AAP                                 BIT(0)
+#define        RCR_MXDMA_OFFSET                        8
+#define        RCR_FIFO_OFFSET                         13
+
+#define RSV_CTRL                               0x001C
+#define RD_CTRL                                        0x0524
+
+#define REG_USB_INFO                           0xFE17
+#define REG_USB_SPECIAL_OPTION                 0xFE55
+#define REG_USB_DMA_AGG_TO                     0xFE5B
+#define REG_USB_AGG_TO                         0xFE5C
+#define REG_USB_AGG_TH                         0xFE5D
+
+#define REG_USB_VID                            0xFE60
+#define REG_USB_PID                            0xFE62
+#define REG_USB_OPTIONAL                       0xFE64
+#define REG_USB_CHIRP_K                                0xFE65
+#define REG_USB_PHY                            0xFE66
+#define REG_USB_MAC_ADDR                       0xFE70
+#define REG_USB_HRPWM                          0xFE58
+#define REG_USB_HCPWM                          0xFE57
+
+#define SW18_FPWM                              BIT(3)
+
+#define ISO_MD2PP                              BIT(0)
+#define ISO_UA2USB                             BIT(1)
+#define ISO_UD2CORE                            BIT(2)
+#define ISO_PA2PCIE                            BIT(3)
+#define ISO_PD2CORE                            BIT(4)
+#define ISO_IP2MAC                             BIT(5)
+#define ISO_DIOP                               BIT(6)
+#define ISO_DIOE                               BIT(7)
+#define ISO_EB2CORE                            BIT(8)
+#define ISO_DIOR                               BIT(9)
+
+#define PWC_EV25V                              BIT(14)
+#define PWC_EV12V                              BIT(15)
+
+#define FEN_BBRSTB                             BIT(0)
+#define FEN_BB_GLB_RSTn                                BIT(1)
+#define FEN_USBA                               BIT(2)
+#define FEN_UPLL                               BIT(3)
+#define FEN_USBD                               BIT(4)
+#define FEN_DIO_PCIE                           BIT(5)
+#define FEN_PCIEA                              BIT(6)
+#define FEN_PPLL                               BIT(7)
+#define FEN_PCIED                              BIT(8)
+#define FEN_DIOE                               BIT(9)
+#define FEN_CPUEN                              BIT(10)
+#define FEN_DCORE                              BIT(11)
+#define FEN_ELDR                               BIT(12)
+#define FEN_DIO_RF                             BIT(13)
+#define FEN_HWPDN                              BIT(14)
+#define FEN_MREGEN                             BIT(15)
+
+#define PFM_LDALL                              BIT(0)
+#define PFM_ALDN                               BIT(1)
+#define PFM_LDKP                               BIT(2)
+#define PFM_WOWL                               BIT(3)
+#define EnPDN                                  BIT(4)
+#define PDN_PL                                 BIT(5)
+#define APFM_ONMAC                             BIT(8)
+#define APFM_OFF                               BIT(9)
+#define APFM_RSM                               BIT(10)
+#define AFSM_HSUS                              BIT(11)
+#define AFSM_PCIE                              BIT(12)
+#define APDM_MAC                               BIT(13)
+#define APDM_HOST                              BIT(14)
+#define APDM_HPDN                              BIT(15)
+#define RDY_MACON                              BIT(16)
+#define SUS_HOST                               BIT(17)
+#define ROP_ALD                                        BIT(20)
+#define ROP_PWR                                        BIT(21)
+#define ROP_SPS                                        BIT(22)
+#define SOP_MRST                               BIT(25)
+#define SOP_FUSE                               BIT(26)
+#define SOP_ABG                                        BIT(27)
+#define SOP_AMB                                        BIT(28)
+#define SOP_RCK                                        BIT(29)
+#define SOP_A8M                                        BIT(30)
+#define XOP_BTCK                               BIT(31)
+
+#define ANAD16V_EN                             BIT(0)
+#define ANA8M                                  BIT(1)
+#define MACSLP                                 BIT(4)
+#define LOADER_CLK_EN                          BIT(5)
+#define _80M_SSC_DIS                           BIT(7)
+#define _80M_SSC_EN_HO                         BIT(8)
+#define PHY_SSC_RSTB                           BIT(9)
+#define SEC_CLK_EN                             BIT(10)
+#define MAC_CLK_EN                             BIT(11)
+#define SYS_CLK_EN                             BIT(12)
+#define RING_CLK_EN                            BIT(13)
+
+#define        BOOT_FROM_EEPROM                        BIT(4)
+#define        EEPROM_EN                               BIT(5)
+
+#define AFE_BGEN                               BIT(0)
+#define AFE_MBEN                               BIT(1)
+#define MAC_ID_EN                              BIT(7)
+
+#define WLOCK_ALL                              BIT(0)
+#define WLOCK_00                               BIT(1)
+#define WLOCK_04                               BIT(2)
+#define WLOCK_08                               BIT(3)
+#define WLOCK_40                               BIT(4)
+#define R_DIS_PRST_0                           BIT(5)
+#define R_DIS_PRST_1                           BIT(6)
+#define LOCK_ALL_EN                            BIT(7)
+
+#define RF_EN                                  BIT(0)
+#define RF_RSTB                                        BIT(1)
+#define RF_SDMRSTB                             BIT(2)
+
+#define LDA15_EN                               BIT(0)
+#define LDA15_STBY                             BIT(1)
+#define LDA15_OBUF                             BIT(2)
+#define LDA15_REG_VOS                          BIT(3)
+#define _LDA15_VOADJ(x)                                (((x) & 0x7) << 4)
+
+#define LDV12_EN                               BIT(0)
+#define LDV12_SDBY                             BIT(1)
+#define LPLDO_HSM                              BIT(2)
+#define LPLDO_LSM_DIS                          BIT(3)
+#define _LDV12_VADJ(x)                         (((x) & 0xF) << 4)
+
+#define XTAL_EN                                        BIT(0)
+#define XTAL_BSEL                              BIT(1)
+#define _XTAL_BOSC(x)                          (((x) & 0x3) << 2)
+#define _XTAL_CADJ(x)                          (((x) & 0xF) << 4)
+#define XTAL_GATE_USB                          BIT(8)
+#define _XTAL_USB_DRV(x)                       (((x) & 0x3) << 9)
+#define XTAL_GATE_AFE                          BIT(11)
+#define _XTAL_AFE_DRV(x)                       (((x) & 0x3) << 12)
+#define XTAL_RF_GATE                           BIT(14)
+#define _XTAL_RF_DRV(x)                                (((x) & 0x3) << 15)
+#define XTAL_GATE_DIG                          BIT(17)
+#define _XTAL_DIG_DRV(x)                       (((x) & 0x3) << 18)
+#define XTAL_BT_GATE                           BIT(20)
+#define _XTAL_BT_DRV(x)                                (((x) & 0x3) << 21)
+#define _XTAL_GPIO(x)                          (((x) & 0x7) << 23)
+
+#define CKDLY_AFE                              BIT(26)
+#define CKDLY_USB                              BIT(27)
+#define CKDLY_DIG                              BIT(28)
+#define CKDLY_BT                               BIT(29)
+
+#define APLL_EN                                        BIT(0)
+#define APLL_320_EN                            BIT(1)
+#define APLL_FREF_SEL                          BIT(2)
+#define APLL_EDGE_SEL                          BIT(3)
+#define APLL_WDOGB                             BIT(4)
+#define APLL_LPFEN                             BIT(5)
+
+#define APLL_REF_CLK_13MHZ                     0x1
+#define APLL_REF_CLK_19_2MHZ                   0x2
+#define APLL_REF_CLK_20MHZ                     0x3
+#define APLL_REF_CLK_25MHZ                     0x4
+#define APLL_REF_CLK_26MHZ                     0x5
+#define APLL_REF_CLK_38_4MHZ                   0x6
+#define APLL_REF_CLK_40MHZ                     0x7
+
+#define APLL_320EN                             BIT(14)
+#define APLL_80EN                              BIT(15)
+#define APLL_1MEN                              BIT(24)
+
+#define ALD_EN                                 BIT(18)
+#define EF_PD                                  BIT(19)
+#define EF_FLAG                                        BIT(31)
+
+#define EF_TRPT                                        BIT(7)
+#define LDOE25_EN                              BIT(31)
+
+#define RSM_EN                                 BIT(0)
+#define Timer_EN                               BIT(4)
+
+#define TRSW0EN                                        BIT(2)
+#define TRSW1EN                                        BIT(3)
+#define EROM_EN                                        BIT(4)
+#define EnBT                                   BIT(5)
+#define EnUart                                 BIT(8)
+#define Uart_910                               BIT(9)
+#define EnPMAC                                 BIT(10)
+#define SIC_SWRST                              BIT(11)
+#define EnSIC                                  BIT(12)
+#define SIC_23                                 BIT(13)
+#define EnHDP                                  BIT(14)
+#define SIC_LBK                                        BIT(15)
+
+#define LED0PL                                 BIT(4)
+#define LED1PL                                 BIT(12)
+#define LED0DIS                                        BIT(7)
+
+#define MCUFWDL_EN                             BIT(0)
+#define MCUFWDL_RDY                            BIT(1)
+#define FWDL_ChkSum_rpt                                BIT(2)
+#define MACINI_RDY                             BIT(3)
+#define BBINI_RDY                              BIT(4)
+#define RFINI_RDY                              BIT(5)
+#define WINTINI_RDY                            BIT(6)
+#define CPRST                                  BIT(23)
+
+#define XCLK_VLD                               BIT(0)
+#define ACLK_VLD                               BIT(1)
+#define UCLK_VLD                               BIT(2)
+#define PCLK_VLD                               BIT(3)
+#define PCIRSTB                                        BIT(4)
+#define V15_VLD                                        BIT(5)
+#define TRP_B15V_EN                            BIT(7)
+#define SIC_IDLE                               BIT(8)
+#define BD_MAC2                                        BIT(9)
+#define BD_MAC1                                        BIT(10)
+#define IC_MACPHY_MODE                         BIT(11)
+#define BT_FUNC                                        BIT(16)
+#define VENDOR_ID                              BIT(19)
+#define PAD_HWPD_IDN                           BIT(22)
+#define TRP_VAUX_EN                            BIT(23)
+#define TRP_BT_EN                              BIT(24)
+#define BD_PKG_SEL                             BIT(25)
+#define BD_HCI_SEL                             BIT(26)
+#define TYPE_ID                                        BIT(27)
+
+#define CHIP_VER_RTL_MASK                      0xF000
+#define CHIP_VER_RTL_SHIFT                     12
+
+#define REG_LBMODE                             (REG_CR + 3)
+
+#define HCI_TXDMA_EN                           BIT(0)
+#define HCI_RXDMA_EN                           BIT(1)
+#define TXDMA_EN                               BIT(2)
+#define RXDMA_EN                               BIT(3)
+#define PROTOCOL_EN                            BIT(4)
+#define SCHEDULE_EN                            BIT(5)
+#define MACTXEN                                        BIT(6)
+#define MACRXEN                                        BIT(7)
+#define ENSWBCN                                        BIT(8)
+#define ENSEC                                  BIT(9)
+
+#define _NETTYPE(x)                            (((x) & 0x3) << 16)
+#define MASK_NETTYPE                           0x30000
+#define NT_NO_LINK                             0x0
+#define NT_LINK_AD_HOC                         0x1
+#define NT_LINK_AP                             0x2
+#define NT_AS_AP                               0x3
+
+#define _LBMODE(x)                             (((x) & 0xF) << 24)
+#define MASK_LBMODE                            0xF000000
+#define LOOPBACK_NORMAL                                0x0
+#define LOOPBACK_IMMEDIATELY                   0xB
+#define LOOPBACK_MAC_DELAY                     0x3
+#define LOOPBACK_PHY                           0x1
+#define LOOPBACK_DMA                           0x7
+
+#define GET_RX_PAGE_SIZE(value)                        ((value) & 0xF)
+#define GET_TX_PAGE_SIZE(value)                        (((value) & 0xF0) >> 4)
+#define _PSRX_MASK                             0xF
+#define _PSTX_MASK                             0xF0
+#define _PSRX(x)                               (x)
+#define _PSTX(x)                               ((x) << 4)
+
+#define PBP_64                                 0x0
+#define PBP_128                                        0x1
+#define PBP_256                                        0x2
+#define PBP_512                                        0x3
+#define PBP_1024                               0x4
+
+#define RXDMA_ARBBW_EN                         BIT(0)
+#define RXSHFT_EN                              BIT(1)
+#define RXDMA_AGG_EN                           BIT(2)
+#define QS_VO_QUEUE                            BIT(8)
+#define QS_VI_QUEUE                            BIT(9)
+#define QS_BE_QUEUE                            BIT(10)
+#define QS_BK_QUEUE                            BIT(11)
+#define QS_MANAGER_QUEUE                       BIT(12)
+#define QS_HIGH_QUEUE                          BIT(13)
+
+#define HQSEL_VOQ                              BIT(0)
+#define HQSEL_VIQ                              BIT(1)
+#define HQSEL_BEQ                              BIT(2)
+#define HQSEL_BKQ                              BIT(3)
+#define HQSEL_MGTQ                             BIT(4)
+#define HQSEL_HIQ                              BIT(5)
+
+#define _TXDMA_HIQ_MAP(x)                      (((x)&0x3) << 14)
+#define _TXDMA_MGQ_MAP(x)                      (((x)&0x3) << 12)
+#define _TXDMA_BKQ_MAP(x)                      (((x)&0x3) << 10)
+#define _TXDMA_BEQ_MAP(x)                      (((x)&0x3) << 8)
+#define _TXDMA_VIQ_MAP(x)                      (((x)&0x3) << 6)
+#define _TXDMA_VOQ_MAP(x)                      (((x)&0x3) << 4)
+
+#define QUEUE_LOW                              1
+#define QUEUE_NORMAL                           2
+#define QUEUE_HIGH                             3
+
+#define _LLT_NO_ACTIVE                         0x0
+#define _LLT_WRITE_ACCESS                      0x1
+#define _LLT_READ_ACCESS                       0x2
+
+#define _LLT_INIT_DATA(x)                      ((x) & 0xFF)
+#define _LLT_INIT_ADDR(x)                      (((x) & 0xFF) << 8)
+#define _LLT_OP(x)                             (((x) & 0x3) << 30)
+#define _LLT_OP_VALUE(x)                       (((x) >> 30) & 0x3)
+
+#define BB_WRITE_READ_MASK                     (BIT(31) | BIT(30))
+#define BB_WRITE_EN                            BIT(30)
+#define BB_READ_EN                             BIT(31)
+
+#define _HPQ(x)                                        ((x) & 0xFF)
+#define _LPQ(x)                                        (((x) & 0xFF) << 8)
+#define _PUBQ(x)                               (((x) & 0xFF) << 16)
+#define _NPQ(x)                                        ((x) & 0xFF)
+
+#define HPQ_PUBLIC_DIS                         BIT(24)
+#define LPQ_PUBLIC_DIS                         BIT(25)
+#define LD_RQPN                                        BIT(31)
+
+#define BCN_VALID                              BIT(16)
+#define BCN_HEAD(x)                            (((x) & 0xFF) << 8)
+#define        BCN_HEAD_MASK                           0xFF00
+
+#define BLK_DESC_NUM_SHIFT                     4
+#define BLK_DESC_NUM_MASK                      0xF
+
+#define DROP_DATA_EN                           BIT(9)
+
+#define EN_AMPDU_RTY_NEW                       BIT(7)
+
+#define _INIRTSMCS_SEL(x)                      ((x) & 0x3F)
+
+#define _SPEC_SIFS_CCK(x)                      ((x) & 0xFF)
+#define _SPEC_SIFS_OFDM(x)                     (((x) & 0xFF) << 8)
+
+#define RATE_REG_BITMAP_ALL                    0xFFFFF
+
+#define _RRSC_BITMAP(x)                                ((x) & 0xFFFFF)
+
+#define _RRSR_RSC(x)                           (((x) & 0x3) << 21)
+#define RRSR_RSC_RESERVED                      0x0
+#define RRSR_RSC_UPPER_SUBCHANNEL              0x1
+#define RRSR_RSC_LOWER_SUBCHANNEL              0x2
+#define RRSR_RSC_DUPLICATE_MODE                        0x3
+
+#define USE_SHORT_G1                           BIT(20)
+
+#define _AGGLMT_MCS0(x)                                ((x) & 0xF)
+#define _AGGLMT_MCS1(x)                                (((x) & 0xF) << 4)
+#define _AGGLMT_MCS2(x)                                (((x) & 0xF) << 8)
+#define _AGGLMT_MCS3(x)                                (((x) & 0xF) << 12)
+#define _AGGLMT_MCS4(x)                                (((x) & 0xF) << 16)
+#define _AGGLMT_MCS5(x)                                (((x) & 0xF) << 20)
+#define _AGGLMT_MCS6(x)                                (((x) & 0xF) << 24)
+#define _AGGLMT_MCS7(x)                                (((x) & 0xF) << 28)
+
+#define        RETRY_LIMIT_SHORT_SHIFT                 8
+#define        RETRY_LIMIT_LONG_SHIFT                  0
+
+#define _DARF_RC1(x)                           ((x) & 0x1F)
+#define _DARF_RC2(x)                           (((x) & 0x1F) << 8)
+#define _DARF_RC3(x)                           (((x) & 0x1F) << 16)
+#define _DARF_RC4(x)                           (((x) & 0x1F) << 24)
+#define _DARF_RC5(x)                           ((x) & 0x1F)
+#define _DARF_RC6(x)                           (((x) & 0x1F) << 8)
+#define _DARF_RC7(x)                           (((x) & 0x1F) << 16)
+#define _DARF_RC8(x)                           (((x) & 0x1F) << 24)
+
+#define _RARF_RC1(x)                           ((x) & 0x1F)
+#define _RARF_RC2(x)                           (((x) & 0x1F) << 8)
+#define _RARF_RC3(x)                           (((x) & 0x1F) << 16)
+#define _RARF_RC4(x)                           (((x) & 0x1F) << 24)
+#define _RARF_RC5(x)                           ((x) & 0x1F)
+#define _RARF_RC6(x)                           (((x) & 0x1F) << 8)
+#define _RARF_RC7(x)                           (((x) & 0x1F) << 16)
+#define _RARF_RC8(x)                           (((x) & 0x1F) << 24)
+
+#define AC_PARAM_TXOP_LIMIT_OFFSET             16
+#define AC_PARAM_ECW_MAX_OFFSET                        12
+#define AC_PARAM_ECW_MIN_OFFSET                        8
+#define AC_PARAM_AIFS_OFFSET                   0
+
+#define _AIFS(x)                               (x)
+#define _ECW_MAX_MIN(x)                                ((x) << 8)
+#define _TXOP_LIMIT(x)                         ((x) << 16)
+
+#define _BCNIFS(x)                             ((x) & 0xFF)
+#define _BCNECW(x)                             ((((x) & 0xF)) << 8)
+
+#define _LRL(x)                                        ((x) & 0x3F)
+#define _SRL(x)                                        (((x) & 0x3F) << 8)
+
+#define _SIFS_CCK_CTX(x)                       ((x) & 0xFF)
+#define _SIFS_CCK_TRX(x)                       (((x) & 0xFF) << 8);
+
+#define _SIFS_OFDM_CTX(x)                      ((x) & 0xFF)
+#define _SIFS_OFDM_TRX(x)                      (((x) & 0xFF) << 8);
+
+#define _TBTT_PROHIBIT_HOLD(x)                 (((x) & 0xFF) << 8)
+
+#define DIS_EDCA_CNT_DWN                       BIT(11)
+
+#define EN_MBSSID                              BIT(1)
+#define EN_TXBCN_RPT                           BIT(2)
+#define        EN_BCN_FUNCTION                         BIT(3)
+
+#define TSFTR_RST                              BIT(0)
+#define TSFTR1_RST                             BIT(1)
+
+#define STOP_BCNQ                              BIT(6)
+
+#define        DIS_TSF_UDT0_NORMAL_CHIP                BIT(4)
+#define        DIS_TSF_UDT0_TEST_CHIP                  BIT(5)
+
+#define        AcmHw_HwEn                              BIT(0)
+#define        AcmHw_BeqEn                             BIT(1)
+#define        AcmHw_ViqEn                             BIT(2)
+#define        AcmHw_VoqEn                             BIT(3)
+#define        AcmHw_BeqStatus                         BIT(4)
+#define        AcmHw_ViqStatus                         BIT(5)
+#define        AcmHw_VoqStatus                         BIT(6)
+
+#define APSDOFF                                        BIT(6)
+#define APSDOFF_STATUS                         BIT(7)
+
+#define BW_20MHZ                               BIT(2)
+
+#define RATE_BITMAP_ALL                                0xFFFFF
+
+#define RATE_RRSR_CCK_ONLY_1M                  0xFFFF1
+
+#define TSFRST                                 BIT(0)
+#define DIS_GCLK                               BIT(1)
+#define PAD_SEL                                        BIT(2)
+#define PWR_ST                                 BIT(6)
+#define PWRBIT_OW_EN                           BIT(7)
+#define ACRC                                   BIT(8)
+#define CFENDFORM                              BIT(9)
+#define ICV                                    BIT(10)
+
+#define AAP                                    BIT(0)
+#define APM                                    BIT(1)
+#define AM                                     BIT(2)
+#define AB                                     BIT(3)
+#define ADD3                                   BIT(4)
+#define APWRMGT                                        BIT(5)
+#define CBSSID                                 BIT(6)
+#define CBSSID_DATA                            BIT(6)
+#define CBSSID_BCN                             BIT(7)
+#define ACRC32                                 BIT(8)
+#define AICV                                   BIT(9)
+#define ADF                                    BIT(11)
+#define ACF                                    BIT(12)
+#define AMF                                    BIT(13)
+#define HTC_LOC_CTRL                           BIT(14)
+#define UC_DATA_EN                             BIT(16)
+#define BM_DATA_EN                             BIT(17)
+#define MFBEN                                  BIT(22)
+#define LSIGEN                                 BIT(23)
+#define EnMBID                                 BIT(24)
+#define APP_BASSN                              BIT(27)
+#define APP_PHYSTS                             BIT(28)
+#define APP_ICV                                        BIT(29)
+#define APP_MIC                                        BIT(30)
+#define APP_FCS                                        BIT(31)
+
+#define _MIN_SPACE(x)                          ((x) & 0x7)
+#define _SHORT_GI_PADDING(x)                   (((x) & 0x1F) << 3)
+
+#define RXERR_TYPE_OFDM_PPDU                   0
+#define RXERR_TYPE_OFDM_FALSE_ALARM            1
+#define        RXERR_TYPE_OFDM_MPDU_OK                 2
+#define RXERR_TYPE_OFDM_MPDU_FAIL              3
+#define RXERR_TYPE_CCK_PPDU                    4
+#define RXERR_TYPE_CCK_FALSE_ALARM             5
+#define RXERR_TYPE_CCK_MPDU_OK                 6
+#define RXERR_TYPE_CCK_MPDU_FAIL               7
+#define RXERR_TYPE_HT_PPDU                     8
+#define RXERR_TYPE_HT_FALSE_ALARM              9
+#define RXERR_TYPE_HT_MPDU_TOTAL               10
+#define RXERR_TYPE_HT_MPDU_OK                  11
+#define RXERR_TYPE_HT_MPDU_FAIL                        12
+#define RXERR_TYPE_RX_FULL_DROP                        15
+
+#define RXERR_COUNTER_MASK                     0xFFFFF
+#define RXERR_RPT_RST                          BIT(27)
+#define _RXERR_RPT_SEL(type)                   ((type) << 28)
+
+#define        SCR_TxUseDK                             BIT(0)
+#define        SCR_RxUseDK                             BIT(1)
+#define        SCR_TxEncEnable                         BIT(2)
+#define        SCR_RxDecEnable                         BIT(3)
+#define        SCR_SKByA2                              BIT(4)
+#define        SCR_NoSKMC                              BIT(5)
+#define SCR_TXBCUSEDK                          BIT(6)
+#define SCR_RXBCUSEDK                          BIT(7)
+
+#define USB_IS_HIGH_SPEED                      0
+#define USB_IS_FULL_SPEED                      1
+#define USB_SPEED_MASK                         BIT(5)
+
+#define USB_NORMAL_SIE_EP_MASK                 0xF
+#define USB_NORMAL_SIE_EP_SHIFT                        4
+
+#define USB_TEST_EP_MASK                       0x30
+#define USB_TEST_EP_SHIFT                      4
+
+#define USB_AGG_EN                             BIT(3)
+
+#define MAC_ADDR_LEN                           6
+#define LAST_ENTRY_OF_TX_PKT_BUFFER            255
+
+#define POLLING_LLT_THRESHOLD                  20
+#define POLLING_READY_TIMEOUT_COUNT            1000
+
+#define        MAX_MSS_DENSITY_2T                      0x13
+#define        MAX_MSS_DENSITY_1T                      0x0A
+
+#define EPROM_CMD_OPERATING_MODE_MASK          ((1<<7)|(1<<6))
+#define EPROM_CMD_CONFIG                       0x3
+#define EPROM_CMD_LOAD                         1
+
+#define        HWSET_MAX_SIZE_92S                      HWSET_MAX_SIZE
+
+#define        HAL_8192C_HW_GPIO_WPS_BIT               BIT(2)
+
+#define        RPMAC_RESET                             0x100
+#define        RPMAC_TXSTART                           0x104
+#define        RPMAC_TXLEGACYSIG                       0x108
+#define        RPMAC_TXHTSIG1                          0x10c
+#define        RPMAC_TXHTSIG2                          0x110
+#define        RPMAC_PHYDEBUG                          0x114
+#define        RPMAC_TXPACKETNUM                       0x118
+#define        RPMAC_TXIDLE                            0x11c
+#define        RPMAC_TXMACHEADER0                      0x120
+#define        RPMAC_TXMACHEADER1                      0x124
+#define        RPMAC_TXMACHEADER2                      0x128
+#define        RPMAC_TXMACHEADER3                      0x12c
+#define        RPMAC_TXMACHEADER4                      0x130
+#define        RPMAC_TXMACHEADER5                      0x134
+#define        RPMAC_TXDADATYPE                        0x138
+#define        RPMAC_TXRANDOMSEED                      0x13c
+#define        RPMAC_CCKPLCPPREAMBLE                   0x140
+#define        RPMAC_CCKPLCPHEADER                     0x144
+#define        RPMAC_CCKCRC16                          0x148
+#define        RPMAC_OFDMRXCRC32OK                     0x170
+#define        RPMAC_OFDMRXCRC32Er                     0x174
+#define        RPMAC_OFDMRXPARITYER                    0x178
+#define        RPMAC_OFDMRXCRC8ER                      0x17c
+#define        RPMAC_CCKCRXRC16ER                      0x180
+#define        RPMAC_CCKCRXRC32ER                      0x184
+#define        RPMAC_CCKCRXRC32OK                      0x188
+#define        RPMAC_TXSTATUS                          0x18c
+
+#define        RFPGA0_RFMOD                            0x800
+
+#define        RFPGA0_TXINFO                           0x804
+#define        RFPGA0_PSDFUNCTION                      0x808
+
+#define        RFPGA0_TXGAINSTAGE                      0x80c
+
+#define        RFPGA0_RFTIMING1                        0x810
+#define        RFPGA0_RFTIMING2                        0x814
+
+#define        RFPGA0_XA_HSSIPARAMETER1                0x820
+#define        RFPGA0_XA_HSSIPARAMETER2                0x824
+#define        RFPGA0_XB_HSSIPARAMETER1                0x828
+#define        RFPGA0_XB_HSSIPARAMETER2                0x82c
+
+#define        RFPGA0_XA_LSSIPARAMETER                 0x840
+#define        RFPGA0_XB_LSSIPARAMETER                 0x844
+
+#define        RFPGA0_RFWAKEUPPARAMETER                0x850
+#define        RFPGA0_RFSLEEPUPPARAMETER               0x854
+
+#define        RFPGA0_XAB_SWITCHCONTROL                0x858
+#define        RFPGA0_XCD_SWITCHCONTROL                0x85c
+
+#define        RFPGA0_XA_RFINTERFACEOE                 0x860
+#define        RFPGA0_XB_RFINTERFACEOE                 0x864
+
+#define        RFPGA0_XAB_RFINTERFACESW                0x870
+#define        RFPGA0_XCD_RFINTERFACESW                0x874
+
+#define        rFPGA0_XAB_RFPARAMETER                  0x878
+#define        rFPGA0_XCD_RFPARAMETER                  0x87c
+
+#define        RFPGA0_ANALOGPARAMETER1                 0x880
+#define        RFPGA0_ANALOGPARAMETER2                 0x884
+#define        RFPGA0_ANALOGPARAMETER3                 0x888
+#define        RFPGA0_ANALOGPARAMETER4                 0x88c
+
+#define        RFPGA0_XA_LSSIREADBACK                  0x8a0
+#define        RFPGA0_XB_LSSIREADBACK                  0x8a4
+#define        RFPGA0_XC_LSSIREADBACK                  0x8a8
+#define        RFPGA0_XD_LSSIREADBACK                  0x8ac
+
+#define        RFPGA0_PSDREPORT                        0x8b4
+#define        TRANSCEIVEA_HSPI_READBACK               0x8b8
+#define        TRANSCEIVEB_HSPI_READBACK               0x8bc
+#define        RFPGA0_XAB_RFINTERFACERB                0x8e0
+#define        RFPGA0_XCD_RFINTERFACERB                0x8e4
+
+#define        RFPGA1_RFMOD                            0x900
+
+#define        RFPGA1_TXBLOCK                          0x904
+#define        RFPGA1_DEBUGSELECT                      0x908
+#define        RFPGA1_TXINFO                           0x90c
+
+#define        RCCK0_SYSTEM                            0xa00
+
+#define        RCCK0_AFESETTING                        0xa04
+#define        RCCK0_CCA                               0xa08
+
+#define        RCCK0_RXAGC1                            0xa0c
+#define        RCCK0_RXAGC2                            0xa10
+
+#define        RCCK0_RXHP                              0xa14
+
+#define        RCCK0_DSPPARAMETER1                     0xa18
+#define        RCCK0_DSPPARAMETER2                     0xa1c
+
+#define        RCCK0_TXFILTER1                         0xa20
+#define        RCCK0_TXFILTER2                         0xa24
+#define        RCCK0_DEBUGPORT                         0xa28
+#define        RCCK0_FALSEALARMREPORT                  0xa2c
+#define        RCCK0_TRSSIREPORT                       0xa50
+#define        RCCK0_RXREPORT                          0xa54
+#define        RCCK0_FACOUNTERLOWER                    0xa5c
+#define        RCCK0_FACOUNTERUPPER                    0xa58
+
+#define        ROFDM0_LSTF                             0xc00
+
+#define        ROFDM0_TRXPATHENABLE                    0xc04
+#define        ROFDM0_TRMUXPAR                         0xc08
+#define        ROFDM0_TRSWISOLATION                    0xc0c
+
+#define        ROFDM0_XARXAFE                          0xc10
+#define        ROFDM0_XARXIQIMBALANCE                  0xc14
+#define        ROFDM0_XBRXAFE                          0xc18
+#define        ROFDM0_XBRXIQIMBALANCE                  0xc1c
+#define        ROFDM0_XCRXAFE                          0xc20
+#define        ROFDM0_XCRXIQIMBANLANCE                 0xc24
+#define        ROFDM0_XDRXAFE                          0xc28
+#define        ROFDM0_XDRXIQIMBALANCE                  0xc2c
+
+#define        ROFDM0_RXDETECTOR1                      0xc30
+#define        ROFDM0_RXDETECTOR2                      0xc34
+#define        ROFDM0_RXDETECTOR3                      0xc38
+#define        ROFDM0_RXDETECTOR4                      0xc3c
+
+#define        ROFDM0_RXDSP                            0xc40
+#define        ROFDM0_CFOANDDAGC                       0xc44
+#define        ROFDM0_CCADROPTHRESHOLD                 0xc48
+#define        ROFDM0_ECCATHRESHOLD                    0xc4c
+
+#define        ROFDM0_XAAGCCORE1                       0xc50
+#define        ROFDM0_XAAGCCORE2                       0xc54
+#define        ROFDM0_XBAGCCORE1                       0xc58
+#define        ROFDM0_XBAGCCORE2                       0xc5c
+#define        ROFDM0_XCAGCCORE1                       0xc60
+#define        ROFDM0_XCAGCCORE2                       0xc64
+#define        ROFDM0_XDAGCCORE1                       0xc68
+#define        ROFDM0_XDAGCCORE2                       0xc6c
+
+#define        ROFDM0_AGCPARAMETER1                    0xc70
+#define        ROFDM0_AGCPARAMETER2                    0xc74
+#define        ROFDM0_AGCRSSITABLE                     0xc78
+#define        ROFDM0_HTSTFAGC                         0xc7c
+
+#define        ROFDM0_XATXIQIMBALANCE                  0xc80
+#define        ROFDM0_XATXAFE                          0xc84
+#define        ROFDM0_XBTXIQIMBALANCE                  0xc88
+#define        ROFDM0_XBTXAFE                          0xc8c
+#define        ROFDM0_XCTXIQIMBALANCE                  0xc90
+#define        ROFDM0_XCTXAFE                          0xc94
+#define        ROFDM0_XDTXIQIMBALANCE                  0xc98
+#define        ROFDM0_XDTXAFE                          0xc9c
+
+#define ROFDM0_RXIQEXTANTA                     0xca0
+
+#define        ROFDM0_RXHPPARAMETER                    0xce0
+#define        ROFDM0_TXPSEUDONOISEWGT                 0xce4
+#define        ROFDM0_FRAMESYNC                        0xcf0
+#define        ROFDM0_DFSREPORT                        0xcf4
+#define        ROFDM0_TXCOEFF1                         0xca4
+#define        ROFDM0_TXCOEFF2                         0xca8
+#define        ROFDM0_TXCOEFF3                         0xcac
+#define        ROFDM0_TXCOEFF4                         0xcb0
+#define        ROFDM0_TXCOEFF5                         0xcb4
+#define        ROFDM0_TXCOEFF6                         0xcb8
+
+#define        ROFDM1_LSTF                             0xd00
+#define        ROFDM1_TRXPATHENABLE                    0xd04
+
+#define        ROFDM1_CF0                              0xd08
+#define        ROFDM1_CSI1                             0xd10
+#define        ROFDM1_SBD                              0xd14
+#define        ROFDM1_CSI2                             0xd18
+#define        ROFDM1_CFOTRACKING                      0xd2c
+#define        ROFDM1_TRXMESAURE1                      0xd34
+#define        ROFDM1_INTFDET                          0xd3c
+#define        ROFDM1_PSEUDONOISESTATEAB               0xd50
+#define        ROFDM1_PSEUDONOISESTATECD               0xd54
+#define        ROFDM1_RXPSEUDONOISEWGT                 0xd58
+
+#define        ROFDM_PHYCOUNTER1                       0xda0
+#define        ROFDM_PHYCOUNTER2                       0xda4
+#define        ROFDM_PHYCOUNTER3                       0xda8
+
+#define        ROFDM_SHORTCFOAB                        0xdac
+#define        ROFDM_SHORTCFOCD                        0xdb0
+#define        ROFDM_LONGCFOAB                         0xdb4
+#define        ROFDM_LONGCFOCD                         0xdb8
+#define        ROFDM_TAILCF0AB                         0xdbc
+#define        ROFDM_TAILCF0CD                         0xdc0
+#define        ROFDM_PWMEASURE1                        0xdc4
+#define        ROFDM_PWMEASURE2                        0xdc8
+#define        ROFDM_BWREPORT                          0xdcc
+#define        ROFDM_AGCREPORT                         0xdd0
+#define        ROFDM_RXSNR                             0xdd4
+#define        ROFDM_RXEVMCSI                          0xdd8
+#define        ROFDM_SIGREPORT                         0xddc
+
+#define        RTXAGC_A_RATE18_06                      0xe00
+#define        RTXAGC_A_RATE54_24                      0xe04
+#define        RTXAGC_A_CCK1_MCS32                     0xe08
+#define        RTXAGC_A_MCS03_MCS00                    0xe10
+#define        RTXAGC_A_MCS07_MCS04                    0xe14
+#define        RTXAGC_A_MCS11_MCS08                    0xe18
+#define        RTXAGC_A_MCS15_MCS12                    0xe1c
+
+#define        RTXAGC_B_RATE18_06                      0x830
+#define        RTXAGC_B_RATE54_24                      0x834
+#define        RTXAGC_B_CCK1_55_MCS32                  0x838
+#define        RTXAGC_B_MCS03_MCS00                    0x83c
+#define        RTXAGC_B_MCS07_MCS04                    0x848
+#define        RTXAGC_B_MCS11_MCS08                    0x84c
+#define        RTXAGC_B_MCS15_MCS12                    0x868
+#define        RTXAGC_B_CCK11_A_CCK2_11                0x86c
+
+#define        RZEBRA1_HSSIENABLE                      0x0
+#define        RZEBRA1_TRXENABLE1                      0x1
+#define        RZEBRA1_TRXENABLE2                      0x2
+#define        RZEBRA1_AGC                             0x4
+#define        RZEBRA1_CHARGEPUMP                      0x5
+#define        RZEBRA1_CHANNEL                         0x7
+
+#define        RZEBRA1_TXGAIN                          0x8
+#define        RZEBRA1_TXLPF                           0x9
+#define        RZEBRA1_RXLPF                           0xb
+#define        RZEBRA1_RXHPFCORNER                     0xc
+
+#define        RGLOBALCTRL                             0
+#define        RRTL8256_TXLPF                          19
+#define        RRTL8256_RXLPF                          11
+#define        RRTL8258_TXLPF                          0x11
+#define        RRTL8258_RXLPF                          0x13
+#define        RRTL8258_RSSILPF                        0xa
+
+#define        RF_AC                                   0x00
+
+#define        RF_IQADJ_G1                             0x01
+#define        RF_IQADJ_G2                             0x02
+#define        RF_POW_TRSW                             0x05
+
+#define        RF_GAIN_RX                              0x06
+#define        RF_GAIN_TX                              0x07
+
+#define        RF_TXM_IDAC                             0x08
+#define        RF_BS_IQGEN                             0x0F
+
+#define        RF_MODE1                                0x10
+#define        RF_MODE2                                0x11
+
+#define        RF_RX_AGC_HP                            0x12
+#define        RF_TX_AGC                               0x13
+#define        RF_BIAS                                 0x14
+#define        RF_IPA                                  0x15
+#define        RF_POW_ABILITY                          0x17
+#define        RF_MODE_AG                              0x18
+#define        RRFCHANNEL                              0x18
+#define        RF_CHNLBW                               0x18
+#define        RF_TOP                                  0x19
+
+#define        RF_RX_G1                                0x1A
+#define        RF_RX_G2                                0x1B
+
+#define        RF_RX_BB2                               0x1C
+#define        RF_RX_BB1                               0x1D
+
+#define        RF_RCK1                                 0x1E
+#define        RF_RCK2                                 0x1F
+
+#define        RF_TX_G1                                0x20
+#define        RF_TX_G2                                0x21
+#define        RF_TX_G3                                0x22
+
+#define        RF_TX_BB1                               0x23
+#define        RF_T_METER                              0x24
+
+#define        RF_SYN_G1                               0x25
+#define        RF_SYN_G2                               0x26
+#define        RF_SYN_G3                               0x27
+#define        RF_SYN_G4                               0x28
+#define        RF_SYN_G5                               0x29
+#define        RF_SYN_G6                               0x2A
+#define        RF_SYN_G7                               0x2B
+#define        RF_SYN_G8                               0x2C
+
+#define        RF_RCK_OS                               0x30
+#define        RF_TXPA_G1                              0x31
+#define        RF_TXPA_G2                              0x32
+#define        RF_TXPA_G3                              0x33
+
+#define        BBBRESETB                               0x100
+#define        BGLOBALRESETB                           0x200
+#define        BOFDMTXSTART                            0x4
+#define        BCCKTXSTART                             0x8
+#define        BCRC32DEBUG                             0x100
+#define        BPMACLOOPBACK                           0x10
+#define        BTXLSIG                                 0xffffff
+#define        BOFDMTXRATE                             0xf
+#define        BOFDMTXRESERVED                         0x10
+#define        BOFDMTXLENGTH                           0x1ffe0
+#define        BOFDMTXPARITY                           0x20000
+#define        BTXHTSIG1                               0xffffff
+#define        BTXHTMCSRATE                            0x7f
+#define        BTXHTBW                                 0x80
+#define        BTXHTLENGTH                             0xffff00
+#define        BTXHTSIG2                               0xffffff
+#define        BTXHTSMOOTHING                          0x1
+#define        BTXHTSOUNDING                           0x2
+#define        BTXHTRESERVED                           0x4
+#define        BTXHTAGGREATION                         0x8
+#define        BTXHTSTBC                               0x30
+#define        BTXHTADVANCECODING                      0x40
+#define        BTXHTSHORTGI                            0x80
+#define        BTXHTNUMBERHT_LTF                       0x300
+#define        BTXHTCRC8                               0x3fc00
+#define        BCOUNTERRESET                           0x10000
+#define        BNUMOFOFDMTX                            0xffff
+#define        BNUMOFCCKTX                             0xffff0000
+#define        BTXIDLEINTERVAL                         0xffff
+#define        BOFDMSERVICE                            0xffff0000
+#define        BTXMACHEADER                            0xffffffff
+#define        BTXDATAINIT                             0xff
+#define        BTXHTMODE                               0x100
+#define        BTXDATATYPE                             0x30000
+#define        BTXRANDOMSEED                           0xffffffff
+#define        BCCKTXPREAMBLE                          0x1
+#define        BCCKTXSFD                               0xffff0000
+#define        BCCKTXSIG                               0xff
+#define        BCCKTXSERVICE                           0xff00
+#define        BCCKLENGTHEXT                           0x8000
+#define        BCCKTXLENGHT                            0xffff0000
+#define        BCCKTXCRC16                             0xffff
+#define        BCCKTXSTATUS                            0x1
+#define        BOFDMTXSTATUS                           0x2
+#define IS_BB_REG_OFFSET_92S(_Offset)  \
+       ((_Offset >= 0x800) && (_Offset <= 0xfff))
+
+#define        BRFMOD                                  0x1
+#define        BJAPANMODE                              0x2
+#define        BCCKTXSC                                0x30
+#define        BCCKEN                                  0x1000000
+#define        BOFDMEN                                 0x2000000
+
+#define        BOFDMRXADCPHASE                         0x10000
+#define        BOFDMTXDACPHASE                         0x40000
+#define        BXATXAGC                                0x3f
+
+#define        BXBTXAGC                                0xf00
+#define        BXCTXAGC                                0xf000
+#define        BXDTXAGC                                0xf0000
+
+#define        BPASTART                                0xf0000000
+#define        BTRSTART                                0x00f00000
+#define        BRFSTART                                0x0000f000
+#define        BBBSTART                                0x000000f0
+#define        BBBCCKSTART                             0x0000000f
+#define        BPAEND                                  0xf
+#define        BTREND                                  0x0f000000
+#define        BRFEND                                  0x000f0000
+#define        BCCAMASK                                0x000000f0
+#define        BR2RCCAMASK                             0x00000f00
+#define        BHSSI_R2TDELAY                          0xf8000000
+#define        BHSSI_T2RDELAY                          0xf80000
+#define        BCONTXHSSI                              0x400
+#define        BIGFROMCCK                              0x200
+#define        BAGCADDRESS                             0x3f
+#define        BRXHPTX                                 0x7000
+#define        BRXHP2RX                                0x38000
+#define        BRXHPCCKINI                             0xc0000
+#define        BAGCTXCODE                              0xc00000
+#define        BAGCRXCODE                              0x300000
+
+#define        B3WIREDATALENGTH                        0x800
+#define        B3WIREADDREAALENGTH                     0x400
+
+#define        B3WIRERFPOWERDOWN                       0x1
+#define        B5GPAPEPOLARITY                         0x40000000
+#define        B2GPAPEPOLARITY                         0x80000000
+#define        BRFSW_TXDEFAULTANT                      0x3
+#define        BRFSW_TXOPTIONANT                       0x30
+#define        BRFSW_RXDEFAULTANT                      0x300
+#define        BRFSW_RXOPTIONANT                       0x3000
+#define        BRFSI_3WIREDATA                         0x1
+#define        BRFSI_3WIRECLOCK                        0x2
+#define        BRFSI_3WIRELOAD                         0x4
+#define        BRFSI_3WIRERW                           0x8
+#define        BRFSI_3WIRE                             0xf
+
+#define        BRFSI_RFENV                             0x10
+
+#define        BRFSI_TRSW                              0x20
+#define        BRFSI_TRSWB                             0x40
+#define        BRFSI_ANTSW                             0x100
+#define        BRFSI_ANTSWB                            0x200
+#define        BRFSI_PAPE                              0x400
+#define        BRFSI_PAPE5G                            0x800
+#define        BBANDSELECT                             0x1
+#define        BHTSIG2_GI                              0x80
+#define        BHTSIG2_SMOOTHING                       0x01
+#define        BHTSIG2_SOUNDING                        0x02
+#define        BHTSIG2_AGGREATON                       0x08
+#define        BHTSIG2_STBC                            0x30
+#define        BHTSIG2_ADVCODING                       0x40
+#define        BHTSIG2_NUMOFHTLTF                      0x300
+#define        BHTSIG2_CRC8                            0x3fc
+#define        BHTSIG1_MCS                             0x7f
+#define        BHTSIG1_BANDWIDTH                       0x80
+#define        BHTSIG1_HTLENGTH                        0xffff
+#define        BLSIG_RATE                              0xf
+#define        BLSIG_RESERVED                          0x10
+#define        BLSIG_LENGTH                            0x1fffe
+#define        BLSIG_PARITY                            0x20
+#define        BCCKRXPHASE                             0x4
+
+#define        BLSSIREADADDRESS                        0x7f800000
+#define        BLSSIREADEDGE                           0x80000000
+
+#define        BLSSIREADBACKDATA                       0xfffff
+
+#define        BLSSIREADOKFLAG                         0x1000
+#define        BCCKSAMPLERATE                          0x8
+#define        BREGULATOR0STANDBY                      0x1
+#define        BREGULATORPLLSTANDBY                    0x2
+#define        BREGULATOR1STANDBY                      0x4
+#define        BPLLPOWERUP                             0x8
+#define        BDPLLPOWERUP                            0x10
+#define        BDA10POWERUP                            0x20
+#define        BAD7POWERUP                             0x200
+#define        BDA6POWERUP                             0x2000
+#define        BXTALPOWERUP                            0x4000
+#define        B40MDCLKPOWERUP                         0x8000
+#define        BDA6DEBUGMODE                           0x20000
+#define        BDA6SWING                               0x380000
+
+#define        BADCLKPHASE                             0x4000000
+#define        B80MCLKDELAY                            0x18000000
+#define        BAFEWATCHDOGENABLE                      0x20000000
+
+#define        BXTALCAP01                              0xc0000000
+#define        BXTALCAP23                              0x3
+#define        BXTALCAP92X                             0x0f000000
+#define BXTALCAP                               0x0f000000
+
+#define        BINTDIFCLKENABLE                        0x400
+#define        BEXTSIGCLKENABLE                        0x800
+#define        BBANDGAP_MBIAS_POWERUP                  0x10000
+#define        BAD11SH_GAIN                            0xc0000
+#define        BAD11NPUT_RANGE                         0x700000
+#define        BAD110P_CURRENT                         0x3800000
+#define        BLPATH_LOOPBACK                         0x4000000
+#define        BQPATH_LOOPBACK                         0x8000000
+#define        BAFE_LOOPBACK                           0x10000000
+#define        BDA10_SWING                             0x7e0
+#define        BDA10_REVERSE                           0x800
+#define        BDA_CLK_SOURCE                          0x1000
+#define        BDA7INPUT_RANGE                         0x6000
+#define        BDA7_GAIN                               0x38000
+#define        BDA7OUTPUT_CM_MODE                      0x40000
+#define        BDA7INPUT_CM_MODE                       0x380000
+#define        BDA7CURRENT                             0xc00000
+#define        BREGULATOR_ADJUST                       0x7000000
+#define        BAD11POWERUP_ATTX                       0x1
+#define        BDA10PS_ATTX                            0x10
+#define        BAD11POWERUP_ATRX                       0x100
+#define        BDA10PS_ATRX                            0x1000
+#define        BCCKRX_AGC_FORMAT                       0x200
+#define        BPSDFFT_SAMPLE_POINT                    0xc000
+#define        BPSD_AVERAGE_NUM                        0x3000
+#define        BIQPATH_CONTROL                         0xc00
+#define        BPSD_FREQ                               0x3ff
+#define        BPSD_ANTENNA_PATH                       0x30
+#define        BPSD_IQ_SWITCH                          0x40
+#define        BPSD_RX_TRIGGER                         0x400000
+#define        BPSD_TX_TRIGGER                         0x80000000
+#define        BPSD_SINE_TONE_SCALE                    0x7f000000
+#define        BPSD_REPORT                             0xffff
+
+#define        BOFDM_TXSC                              0x30000000
+#define        BCCK_TXON                               0x1
+#define        BOFDM_TXON                              0x2
+#define        BDEBUG_PAGE                             0xfff
+#define        BDEBUG_ITEM                             0xff
+#define        BANTL                                   0x10
+#define        BANT_NONHT                              0x100
+#define        BANT_HT1                                0x1000
+#define        BANT_HT2                                0x10000
+#define        BANT_HT1S1                              0x100000
+#define        BANT_NONHTS1                            0x1000000
+
+#define        BCCK_BBMODE                             0x3
+#define        BCCK_TXPOWERSAVING                      0x80
+#define        BCCK_RXPOWERSAVING                      0x40
+
+#define        BCCK_SIDEBAND                           0x10
+
+#define        BCCK_SCRAMBLE                           0x8
+#define        BCCK_ANTDIVERSITY                       0x8000
+#define        BCCK_CARRIER_RECOVERY                   0x4000
+#define        BCCK_TXRATE                             0x3000
+#define        BCCK_DCCANCEL                           0x0800
+#define        BCCK_ISICANCEL                          0x0400
+#define        BCCK_MATCH_FILTER                       0x0200
+#define        BCCK_EQUALIZER                          0x0100
+#define        BCCK_PREAMBLE_DETECT                    0x800000
+#define        BCCK_FAST_FALSECCAi                     0x400000
+#define        BCCK_CH_ESTSTARTi                       0x300000
+#define        BCCK_CCA_COUNTi                         0x080000
+#define        BCCK_CS_LIM                             0x070000
+#define        BCCK_BIST_MODEi                         0x80000000
+#define        BCCK_CCAMASK                            0x40000000
+#define        BCCK_TX_DAC_PHASE                       0x4
+#define        BCCK_RX_ADC_PHASE                       0x20000000
+#define        BCCKR_CP_MODE                           0x0100
+#define        BCCK_TXDC_OFFSET                        0xf0
+#define        BCCK_RXDC_OFFSET                        0xf
+#define        BCCK_CCA_MODE                           0xc000
+#define        BCCK_FALSECS_LIM                        0x3f00
+#define        BCCK_CS_RATIO                           0xc00000
+#define        BCCK_CORGBIT_SEL                        0x300000
+#define        BCCK_PD_LIM                             0x0f0000
+#define        BCCK_NEWCCA                             0x80000000
+#define        BCCK_RXHP_OF_IG                         0x8000
+#define        BCCK_RXIG                               0x7f00
+#define        BCCK_LNA_POLARITY                       0x800000
+#define        BCCK_RX1ST_BAIN                         0x7f0000
+#define        BCCK_RF_EXTEND                          0x20000000
+#define        BCCK_RXAGC_SATLEVEL                     0x1f000000
+#define        BCCK_RXAGC_SATCOUNT                     0xe0
+#define        bCCKRxRFSettle                          0x1f
+#define        BCCK_FIXED_RXAGC                        0x8000
+#define        BCCK_ANTENNA_POLARITY                   0x2000
+#define        BCCK_TXFILTER_TYPE                      0x0c00
+#define        BCCK_RXAGC_REPORTTYPE                   0x0300
+#define        BCCK_RXDAGC_EN                          0x80000000
+#define        BCCK_RXDAGC_PERIOD                      0x20000000
+#define        BCCK_RXDAGC_SATLEVEL                    0x1f000000
+#define        BCCK_TIMING_RECOVERY                    0x800000
+#define        BCCK_TXC0                               0x3f0000
+#define        BCCK_TXC1                               0x3f000000
+#define        BCCK_TXC2                               0x3f
+#define        BCCK_TXC3                               0x3f00
+#define        BCCK_TXC4                               0x3f0000
+#define        BCCK_TXC5                               0x3f000000
+#define        BCCK_TXC6                               0x3f
+#define        BCCK_TXC7                               0x3f00
+#define        BCCK_DEBUGPORT                          0xff0000
+#define        BCCK_DAC_DEBUG                          0x0f000000
+#define        BCCK_FALSEALARM_ENABLE                  0x8000
+#define        BCCK_FALSEALARM_READ                    0x4000
+#define        BCCK_TRSSI                              0x7f
+#define        BCCK_RXAGC_REPORT                       0xfe
+#define        BCCK_RXREPORT_ANTSEL                    0x80000000
+#define        BCCK_RXREPORT_MFOFF                     0x40000000
+#define        BCCK_RXREPORT_SQLOSS                    0x20000000
+#define        BCCK_RXREPORT_PKTLOSS                   0x10000000
+#define        BCCK_RXREPORT_LOCKEDBIT                 0x08000000
+#define        BCCK_RXREPORT_RATEERROR                 0x04000000
+#define        BCCK_RXREPORT_RXRATE                    0x03000000
+#define        BCCK_RXFA_COUNTER_LOWER                 0xff
+#define        BCCK_RXFA_COUNTER_UPPER                 0xff000000
+#define        BCCK_RXHPAGC_START                      0xe000
+#define        BCCK_RXHPAGC_FINAL                      0x1c00
+#define        BCCK_RXFALSEALARM_ENABLE                0x8000
+#define        BCCK_FACOUNTER_FREEZE                   0x4000
+#define        BCCK_TXPATH_SEL                         0x10000000
+#define        BCCK_DEFAULT_RXPATH                     0xc000000
+#define        BCCK_OPTION_RXPATH                      0x3000000
+
+#define        BNUM_OFSTF                              0x3
+#define        BSHIFT_L                                0xc0
+#define        BGI_TH                                  0xc
+#define        BRXPATH_A                               0x1
+#define        BRXPATH_B                               0x2
+#define        BRXPATH_C                               0x4
+#define        BRXPATH_D                               0x8
+#define        BTXPATH_A                               0x1
+#define        BTXPATH_B                               0x2
+#define        BTXPATH_C                               0x4
+#define        BTXPATH_D                               0x8
+#define        BTRSSI_FREQ                             0x200
+#define        BADC_BACKOFF                            0x3000
+#define        BDFIR_BACKOFF                           0xc000
+#define        BTRSSI_LATCH_PHASE                      0x10000
+#define        BRX_LDC_OFFSET                          0xff
+#define        BRX_QDC_OFFSET                          0xff00
+#define        BRX_DFIR_MODE                           0x1800000
+#define        BRX_DCNF_TYPE                           0xe000000
+#define        BRXIQIMB_A                              0x3ff
+#define        BRXIQIMB_B                              0xfc00
+#define        BRXIQIMB_C                              0x3f0000
+#define        BRXIQIMB_D                              0xffc00000
+#define        BDC_DC_NOTCH                            0x60000
+#define        BRXNB_NOTCH                             0x1f000000
+#define        BPD_TH                                  0xf
+#define        BPD_TH_OPT2                             0xc000
+#define        BPWED_TH                                0x700
+#define        BIFMF_WIN_L                             0x800
+#define        BPD_OPTION                              0x1000
+#define        BMF_WIN_L                               0xe000
+#define        BBW_SEARCH_L                            0x30000
+#define        BWIN_ENH_L                              0xc0000
+#define        BBW_TH                                  0x700000
+#define        BED_TH2                                 0x3800000
+#define        BBW_OPTION                              0x4000000
+#define        BRADIO_TH                               0x18000000
+#define        BWINDOW_L                               0xe0000000
+#define        BSBD_OPTION                             0x1
+#define        BFRAME_TH                               0x1c
+#define        BFS_OPTION                              0x60
+#define        BDC_SLOPE_CHECK                         0x80
+#define        BFGUARD_COUNTER_DC_L                    0xe00
+#define        BFRAME_WEIGHT_SHORT                     0x7000
+#define        BSUB_TUNE                               0xe00000
+#define        BFRAME_DC_LENGTH                        0xe000000
+#define        BSBD_START_OFFSET                       0x30000000
+#define        BFRAME_TH_2                             0x7
+#define        BFRAME_GI2_TH                           0x38
+#define        BGI2_SYNC_EN                            0x40
+#define        BSARCH_SHORT_EARLY                      0x300
+#define        BSARCH_SHORT_LATE                       0xc00
+#define        BSARCH_GI2_LATE                         0x70000
+#define        BCFOANTSUM                              0x1
+#define        BCFOACC                                 0x2
+#define        BCFOSTARTOFFSET                         0xc
+#define        BCFOLOOPBACK                            0x70
+#define        BCFOSUMWEIGHT                           0x80
+#define        BDAGCENABLE                             0x10000
+#define        BTXIQIMB_A                              0x3ff
+#define        BTXIQIMB_b                              0xfc00
+#define        BTXIQIMB_C                              0x3f0000
+#define        BTXIQIMB_D                              0xffc00000
+#define        BTXIDCOFFSET                            0xff
+#define        BTXIQDCOFFSET                           0xff00
+#define        BTXDFIRMODE                             0x10000
+#define        BTXPESUDO_NOISEON                       0x4000000
+#define        BTXPESUDO_NOISE_A                       0xff
+#define        BTXPESUDO_NOISE_B                       0xff00
+#define        BTXPESUDO_NOISE_C                       0xff0000
+#define        BTXPESUDO_NOISE_D                       0xff000000
+#define        BCCA_DROPOPTION                         0x20000
+#define        BCCA_DROPTHRES                          0xfff00000
+#define        BEDCCA_H                                0xf
+#define        BEDCCA_L                                0xf0
+#define        BLAMBDA_ED                              0x300
+#define        BRX_INITIALGAIN                         0x7f
+#define        BRX_ANTDIV_EN                           0x80
+#define        BRX_AGC_ADDRESS_FOR_LNA                 0x7f00
+#define        BRX_HIGHPOWER_FLOW                      0x8000
+#define        BRX_AGC_FREEZE_THRES                    0xc0000
+#define        BRX_FREEZESTEP_AGC1                     0x300000
+#define        BRX_FREEZESTEP_AGC2                     0xc00000
+#define        BRX_FREEZESTEP_AGC3                     0x3000000
+#define        BRX_FREEZESTEP_AGC0                     0xc000000
+#define        BRXRSSI_CMP_EN                          0x10000000
+#define        BRXQUICK_AGCEN                          0x20000000
+#define        BRXAGC_FREEZE_THRES_MODE                0x40000000
+#define        BRX_OVERFLOW_CHECKTYPE                  0x80000000
+#define        BRX_AGCSHIFT                            0x7f
+#define        BTRSW_TRI_ONLY                          0x80
+#define        BPOWER_THRES                            0x300
+#define        BRXAGC_EN                               0x1
+#define        BRXAGC_TOGETHER_EN                      0x2
+#define        BRXAGC_MIN                              0x4
+#define        BRXHP_INI                               0x7
+#define        BRXHP_TRLNA                             0x70
+#define        BRXHP_RSSI                              0x700
+#define        BRXHP_BBP1                              0x7000
+#define        BRXHP_BBP2                              0x70000
+#define        BRXHP_BBP3                              0x700000
+#define        BRSSI_H                                 0x7f0000
+#define        BRSSI_GEN                               0x7f000000
+#define        BRXSETTLE_TRSW                          0x7
+#define        BRXSETTLE_LNA                           0x38
+#define        BRXSETTLE_RSSI                          0x1c0
+#define        BRXSETTLE_BBP                           0xe00
+#define        BRXSETTLE_RXHP                          0x7000
+#define        BRXSETTLE_ANTSW_RSSI                    0x38000
+#define        BRXSETTLE_ANTSW                         0xc0000
+#define        BRXPROCESS_TIME_DAGC                    0x300000
+#define        BRXSETTLE_HSSI                          0x400000
+#define        BRXPROCESS_TIME_BBPPW                   0x800000
+#define        BRXANTENNA_POWER_SHIFT                  0x3000000
+#define        BRSSI_TABLE_SELECT                      0xc000000
+#define        BRXHP_FINAL                             0x7000000
+#define        BRXHPSETTLE_BBP                         0x7
+#define        BRXHTSETTLE_HSSI                        0x8
+#define        BRXHTSETTLE_RXHP                        0x70
+#define        BRXHTSETTLE_BBPPW                       0x80
+#define        BRXHTSETTLE_IDLE                        0x300
+#define        BRXHTSETTLE_RESERVED                    0x1c00
+#define        BRXHT_RXHP_EN                           0x8000
+#define        BRXAGC_FREEZE_THRES                     0x30000
+#define        BRXAGC_TOGETHEREN                       0x40000
+#define        BRXHTAGC_MIN                            0x80000
+#define        BRXHTAGC_EN                             0x100000
+#define        BRXHTDAGC_EN                            0x200000
+#define        BRXHT_RXHP_BBP                          0x1c00000
+#define        BRXHT_RXHP_FINAL                        0xe0000000
+#define        BRXPW_RADIO_TH                          0x3
+#define        BRXPW_RADIO_EN                          0x4
+#define        BRXMF_HOLD                              0x3800
+#define        BRXPD_DELAY_TH1                         0x38
+#define        BRXPD_DELAY_TH2                         0x1c0
+#define        BRXPD_DC_COUNT_MAX                      0x600
+#define        BRXPD_DELAY_TH                          0x8000
+#define        BRXPROCESS_DELAY                        0xf0000
+#define        BRXSEARCHRANGE_GI2_EARLY                0x700000
+#define        BRXFRAME_FUARD_COUNTER_L                0x3800000
+#define        BRXSGI_GUARD_L                          0xc000000
+#define        BRXSGI_SEARCH_L                         0x30000000
+#define        BRXSGI_TH                               0xc0000000
+#define        BDFSCNT0                                0xff
+#define        BDFSCNT1                                0xff00
+#define        BDFSFLAG                                0xf0000
+#define        BMF_WEIGHT_SUM                          0x300000
+#define        BMINIDX_TH                              0x7f000000
+#define        BDAFORMAT                               0x40000
+#define        BTXCH_EMU_ENABLE                        0x01000000
+#define        BTRSW_ISOLATION_A                       0x7f
+#define        BTRSW_ISOLATION_B                       0x7f00
+#define        BTRSW_ISOLATION_C                       0x7f0000
+#define        BTRSW_ISOLATION_D                       0x7f000000
+#define        BEXT_LNA_GAIN                           0x7c00
+
+#define        BSTBC_EN                                0x4
+#define        BANTENNA_MAPPING                        0x10
+#define        BNSS                                    0x20
+#define        BCFO_ANTSUM_ID                          0x200
+#define        BPHY_COUNTER_RESET                      0x8000000
+#define        BCFO_REPORT_GET                         0x4000000
+#define        BOFDM_CONTINUE_TX                       0x10000000
+#define        BOFDM_SINGLE_CARRIER                    0x20000000
+#define        BOFDM_SINGLE_TONE                       0x40000000
+#define        BHT_DETECT                              0x100
+#define        BCFOEN                                  0x10000
+#define        BCFOVALUE                               0xfff00000
+#define        BSIGTONE_RE                             0x3f
+#define        BSIGTONE_IM                             0x7f00
+#define        BCOUNTER_CCA                            0xffff
+#define        BCOUNTER_PARITYFAIL                     0xffff0000
+#define        BCOUNTER_RATEILLEGAL                    0xffff
+#define        BCOUNTER_CRC8FAIL                       0xffff0000
+#define        BCOUNTER_MCSNOSUPPORT                   0xffff
+#define        BCOUNTER_FASTSYNC                       0xffff
+#define        BSHORTCFO                               0xfff
+#define        BSHORTCFOT_LENGTH                       12
+#define        BSHORTCFOF_LENGTH                       11
+#define        BLONGCFO                                0x7ff
+#define        BLONGCFOT_LENGTH                        11
+#define        BLONGCFOF_LENGTH                        11
+#define        BTAILCFO                                0x1fff
+#define        BTAILCFOT_LENGTH                        13
+#define        BTAILCFOF_LENGTH                        12
+#define        BNOISE_EN_PWDB                          0xffff
+#define        BCC_POWER_DB                            0xffff0000
+#define        BMOISE_PWDB                             0xffff
+#define        BPOWERMEAST_LENGTH                      10
+#define        BPOWERMEASF_LENGTH                      3
+#define        BRX_HT_BW                               0x1
+#define        BRXSC                                   0x6
+#define        BRX_HT                                  0x8
+#define        BNB_INTF_DET_ON                         0x1
+#define        BINTF_WIN_LEN_CFG                       0x30
+#define        BNB_INTF_TH_CFG                         0x1c0
+#define        BRFGAIN                                 0x3f
+#define        BTABLESEL                               0x40
+#define        BTRSW                                   0x80
+#define        BRXSNR_A                                0xff
+#define        BRXSNR_B                                0xff00
+#define        BRXSNR_C                                0xff0000
+#define        BRXSNR_D                                0xff000000
+#define        BSNR_EVMT_LENGTH                        8
+#define        BSNR_EVMF_LENGTH                        1
+#define        BCSI1ST                                 0xff
+#define        BCSI2ND                                 0xff00
+#define        BRXEVM1ST                               0xff0000
+#define        BRXEVM2ND                               0xff000000
+#define        BSIGEVM                                 0xff
+#define        BPWDB                                   0xff00
+#define        BSGIEN                                  0x10000
+
+#define        BSFACTOR_QMA1                           0xf
+#define        BSFACTOR_QMA2                           0xf0
+#define        BSFACTOR_QMA3                           0xf00
+#define        BSFACTOR_QMA4                           0xf000
+#define        BSFACTOR_QMA5                           0xf0000
+#define        BSFACTOR_QMA6                           0xf0000
+#define        BSFACTOR_QMA7                           0xf00000
+#define        BSFACTOR_QMA8                           0xf000000
+#define        BSFACTOR_QMA9                           0xf0000000
+#define        BCSI_SCHEME                             0x100000
+
+#define        BNOISE_LVL_TOP_SET                      0x3
+#define        BCHSMOOTH                               0x4
+#define        BCHSMOOTH_CFG1                          0x38
+#define        BCHSMOOTH_CFG2                          0x1c0
+#define        BCHSMOOTH_CFG3                          0xe00
+#define        BCHSMOOTH_CFG4                          0x7000
+#define        BMRCMODE                                0x800000
+#define        BTHEVMCFG                               0x7000000
+
+#define        BLOOP_FIT_TYPE                          0x1
+#define        BUPD_CFO                                0x40
+#define        BUPD_CFO_OFFDATA                        0x80
+#define        BADV_UPD_CFO                            0x100
+#define        BADV_TIME_CTRL                          0x800
+#define        BUPD_CLKO                               0x1000
+#define        BFC                                     0x6000
+#define        BTRACKING_MODE                          0x8000
+#define        BPHCMP_ENABLE                           0x10000
+#define        BUPD_CLKO_LTF                           0x20000
+#define        BCOM_CH_CFO                             0x40000
+#define        BCSI_ESTI_MODE                          0x80000
+#define        BADV_UPD_EQZ                            0x100000
+#define        BUCHCFG                                 0x7000000
+#define        BUPDEQZ                                 0x8000000
+
+#define        BRX_PESUDO_NOISE_ON                     0x20000000
+#define        BRX_PESUDO_NOISE_A                      0xff
+#define        BRX_PESUDO_NOISE_B                      0xff00
+#define        BRX_PESUDO_NOISE_C                      0xff0000
+#define        BRX_PESUDO_NOISE_D                      0xff000000
+#define        BRX_PESUDO_NOISESTATE_A                 0xffff
+#define        BRX_PESUDO_NOISESTATE_B                 0xffff0000
+#define        BRX_PESUDO_NOISESTATE_C                 0xffff
+#define        BRX_PESUDO_NOISESTATE_D                 0xffff0000
+
+#define        BZEBRA1_HSSIENABLE                      0x8
+#define        BZEBRA1_TRXCONTROL                      0xc00
+#define        BZEBRA1_TRXGAINSETTING                  0x07f
+#define        BZEBRA1_RXCOUNTER                       0xc00
+#define        BZEBRA1_TXCHANGEPUMP                    0x38
+#define        BZEBRA1_RXCHANGEPUMP                    0x7
+#define        BZEBRA1_CHANNEL_NUM                     0xf80
+#define        BZEBRA1_TXLPFBW                         0x400
+#define        BZEBRA1_RXLPFBW                         0x600
+
+#define        BRTL8256REG_MODE_CTRL1                  0x100
+#define        BRTL8256REG_MODE_CTRL0                  0x40
+#define        BRTL8256REG_TXLPFBW                     0x18
+#define        BRTL8256REG_RXLPFBW                     0x600
+
+#define        BRTL8258_TXLPFBW                        0xc
+#define        BRTL8258_RXLPFBW                        0xc00
+#define        BRTL8258_RSSILPFBW                      0xc0
+
+#define        BBYTE0                                  0x1
+#define        BBYTE1                                  0x2
+#define        BBYTE2                                  0x4
+#define        BBYTE3                                  0x8
+#define        BWORD0                                  0x3
+#define        BWORD1                                  0xc
+#define        BWORD                                   0xf
+
+#define        MASKBYTE0                               0xff
+#define        MASKBYTE1                               0xff00
+#define        MASKBYTE2                               0xff0000
+#define        MASKBYTE3                               0xff000000
+#define        MASKHWORD                               0xffff0000
+#define        MASKLWORD                               0x0000ffff
+#define        MASKDWORD                               0xffffffff
+#define        MASK12BITS                              0xfff
+#define        MASKH4BITS                              0xf0000000
+#define MASKOFDM_D                             0xffc00000
+#define        MASKCCK                                 0x3f3f3f3f
+
+#define        MASK4BITS                               0x0f
+#define        MASK20BITS                              0xfffff
+#define RFREG_OFFSET_MASK                      0xfffff
+
+#define        BENABLE                                 0x1
+#define        BDISABLE                                0x0
+
+#define        LEFT_ANTENNA                            0x0
+#define        RIGHT_ANTENNA                           0x1
+
+#define        TCHECK_TXSTATUS                         500
+#define        TUPDATE_RXCOUNTER                       100
+
+/* 2 EFUSE_TEST (For RTL8723 partially) */
+#define EFUSE_SEL(x)                           (((x) & 0x3) << 8)
+#define EFUSE_SEL_MASK                         0x300
+#define EFUSE_WIFI_SEL_0                       0x0
+
+/* Enable GPIO[9] as WiFi HW PDn source*/
+#define        WL_HWPDN_EN                             BIT(0)
+/* WiFi HW PDn polarity control*/
+#define        WL_HWPDN_SL                             BIT(1)
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/rf.c b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.c
new file mode 100644 (file)
index 0000000..50dd2fb
--- /dev/null
@@ -0,0 +1,505 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "rf.h"
+#include "dm.h"
+
+void rtl8723ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw, u8 bandwidth)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       switch (bandwidth) {
+       case HT_CHANNEL_WIDTH_20:
+               rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+                                            0xfffff3ff) | 0x0400);
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+                             rtlphy->rfreg_chnlval[0]);
+               break;
+       case HT_CHANNEL_WIDTH_20_40:
+               rtlphy->rfreg_chnlval[0] = ((rtlphy->rfreg_chnlval[0] &
+                                            0xfffff3ff));
+               rtl_set_rfreg(hw, RF90_PATH_A, RF_CHNLBW, RFREG_OFFSET_MASK,
+                             rtlphy->rfreg_chnlval[0]);
+               break;
+       default:
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "unknown bandwidth: %#X\n", bandwidth);
+               break;
+       }
+}
+
+void rtl8723ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+                                         u8 *ppowerlevel)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u32 tx_agc[2] = {0, 0}, tmpval;
+       bool turbo_scanoff = false;
+       u8 idx1, idx2;
+       u8 *ptr;
+
+       if (rtlefuse->eeprom_regulatory != 0)
+               turbo_scanoff = true;
+
+       if (mac->act_scanning == true) {
+               tx_agc[RF90_PATH_A] = 0x3f3f3f3f;
+               tx_agc[RF90_PATH_B] = 0x3f3f3f3f;
+
+               if (turbo_scanoff) {
+                       for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+                               tx_agc[idx1] = ppowerlevel[idx1] |
+                                   (ppowerlevel[idx1] << 8) |
+                                   (ppowerlevel[idx1] << 16) |
+                                   (ppowerlevel[idx1] << 24);
+                       }
+               }
+       } else {
+               for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+                       tx_agc[idx1] = ppowerlevel[idx1] |
+                                      (ppowerlevel[idx1] << 8) |
+                                      (ppowerlevel[idx1] << 16) |
+                                      (ppowerlevel[idx1] << 24);
+               }
+
+               if (rtlefuse->eeprom_regulatory == 0) {
+                       tmpval = (rtlphy->mcs_offset[0][6]) +
+                               (rtlphy->mcs_offset[0][7] << 8);
+                       tx_agc[RF90_PATH_A] += tmpval;
+
+                       tmpval = (rtlphy->mcs_offset[0][14]) +
+                           (rtlphy->mcs_offset[0][15] << 24);
+                       tx_agc[RF90_PATH_B] += tmpval;
+               }
+       }
+
+       for (idx1 = RF90_PATH_A; idx1 <= RF90_PATH_B; idx1++) {
+               ptr = (u8 *) (&(tx_agc[idx1]));
+               for (idx2 = 0; idx2 < 4; idx2++) {
+                       if (*ptr > RF6052_MAX_TX_PWR)
+                               *ptr = RF6052_MAX_TX_PWR;
+                       ptr++;
+               }
+       }
+
+       tmpval = tx_agc[RF90_PATH_A] & 0xff;
+       rtl_set_bbreg(hw, RTXAGC_A_CCK1_MCS32, MASKBYTE1, tmpval);
+
+       RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+               "CCK PWR 1M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+               RTXAGC_A_CCK1_MCS32);
+
+       tmpval = tx_agc[RF90_PATH_A] >> 8;
+
+       tmpval = tmpval & 0xff00ffff;
+
+       rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, 0xffffff00, tmpval);
+
+       RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+               "CCK PWR 2~11M (rf-A) = 0x%x (reg 0x%x)\n", tmpval,
+               RTXAGC_B_CCK11_A_CCK2_11);
+
+       tmpval = tx_agc[RF90_PATH_B] >> 24;
+       rtl_set_bbreg(hw, RTXAGC_B_CCK11_A_CCK2_11, MASKBYTE0, tmpval);
+
+       RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+               "CCK PWR 11M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+               RTXAGC_B_CCK11_A_CCK2_11);
+
+       tmpval = tx_agc[RF90_PATH_B] & 0x00ffffff;
+       rtl_set_bbreg(hw, RTXAGC_B_CCK1_55_MCS32, 0xffffff00, tmpval);
+
+       RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+               "CCK PWR 1~5.5M (rf-B) = 0x%x (reg 0x%x)\n", tmpval,
+               RTXAGC_B_CCK1_55_MCS32);
+}
+
+static void rtl8723ae_phy_get_power_base(struct ieee80211_hw *hw,
+                                        u8 *ppowerlevel, u8 channel,
+                                        u32 *ofdmbase, u32 *mcsbase)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u32 powerBase0, powerBase1;
+       u8 legacy_pwrdiff, ht20_pwrdiff;
+       u8 i, powerlevel[2];
+
+       for (i = 0; i < 2; i++) {
+               powerlevel[i] = ppowerlevel[i];
+               legacy_pwrdiff = rtlefuse->txpwr_legacyhtdiff[i][channel - 1];
+               powerBase0 = powerlevel[i] + legacy_pwrdiff;
+
+               powerBase0 = (powerBase0 << 24) | (powerBase0 << 16) |
+                   (powerBase0 << 8) | powerBase0;
+               *(ofdmbase + i) = powerBase0;
+               RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                       " [OFDM power base index rf(%c) = 0x%x]\n",
+                       ((i == 0) ? 'A' : 'B'), *(ofdmbase + i));
+       }
+
+       for (i = 0; i < 2; i++) {
+               if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20) {
+                       ht20_pwrdiff = rtlefuse->txpwr_ht20diff[i][channel - 1];
+                       powerlevel[i] += ht20_pwrdiff;
+               }
+               powerBase1 = powerlevel[i];
+               powerBase1 = (powerBase1 << 24) |
+                   (powerBase1 << 16) | (powerBase1 << 8) | powerBase1;
+
+               *(mcsbase + i) = powerBase1;
+
+               RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                       " [MCS power base index rf(%c) = 0x%x]\n",
+                       ((i == 0) ? 'A' : 'B'), *(mcsbase + i));
+       }
+}
+
+static void rtl8723ae_get_txpwr_val_by_reg(struct ieee80211_hw *hw,
+                                          u8 channel, u8 index,
+                                          u32 *powerBase0,
+                                          u32 *powerBase1,
+                                          u32 *p_outwriteval)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       u8 i, chnlgroup = 0, pwr_diff_limit[4];
+       u32 writeVal, customer_limit, rf;
+
+       for (rf = 0; rf < 2; rf++) {
+               switch (rtlefuse->eeprom_regulatory) {
+               case 0:
+                       chnlgroup = 0;
+
+                       writeVal = rtlphy->mcs_offset[chnlgroup]
+                                  [index + (rf ? 8 : 0)] +
+                                  ((index < 2) ? powerBase0[rf] :
+                                  powerBase1[rf]);
+
+                       RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                               "RTK better performance, "
+                               "writeVal(%c) = 0x%x\n",
+                               ((rf == 0) ? 'A' : 'B'), writeVal);
+                       break;
+               case 1:
+                       if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+                               writeVal = ((index < 2) ? powerBase0[rf] :
+                                           powerBase1[rf]);
+
+                               RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                                       "Realtek regulatory, 40MHz, "
+                                       "writeVal(%c) = 0x%x\n",
+                                       ((rf == 0) ? 'A' : 'B'), writeVal);
+                       } else {
+                               if (rtlphy->pwrgroup_cnt == 1)
+                                       chnlgroup = 0;
+                               if (rtlphy->pwrgroup_cnt >= 3) {
+                                       if (channel <= 3)
+                                               chnlgroup = 0;
+                                       else if (channel >= 4 && channel <= 9)
+                                               chnlgroup = 1;
+                                       else if (channel > 9)
+                                               chnlgroup = 2;
+                                       if (rtlphy->current_chan_bw ==
+                                           HT_CHANNEL_WIDTH_20)
+                                               chnlgroup++;
+                                       else
+                                               chnlgroup += 4;
+                               }
+
+                               writeVal = rtlphy->mcs_offset[chnlgroup]
+                                   [index + (rf ? 8 : 0)] + ((index < 2) ?
+                                                             powerBase0[rf] :
+                                                             powerBase1[rf]);
+
+                               RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                                       "Realtek regulatory, 20MHz, writeVal(%c) = 0x%x\n",
+                                       ((rf == 0) ? 'A' : 'B'), writeVal);
+                       }
+                       break;
+               case 2:
+                       writeVal =
+                           ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+
+                       RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                               "Better regulatory, writeVal(%c) = 0x%x\n",
+                               ((rf == 0) ? 'A' : 'B'), writeVal);
+                       break;
+               case 3:
+                       chnlgroup = 0;
+
+                       if (rtlphy->current_chan_bw == HT_CHANNEL_WIDTH_20_40) {
+                               RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                                       "customer's limit, 40MHz rf(%c) = 0x%x\n",
+                                       ((rf == 0) ? 'A' : 'B'),
+                                       rtlefuse->pwrgroup_ht40[rf][channel-1]);
+                       } else {
+                               RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                                       "customer's limit, 20MHz rf(%c) = 0x%x\n",
+                                       ((rf == 0) ? 'A' : 'B'),
+                                       rtlefuse->pwrgroup_ht20[rf][channel-1]);
+                       }
+                       for (i = 0; i < 4; i++) {
+                               pwr_diff_limit[i] =
+                                       (u8) ((rtlphy->mcs_offset
+                                       [chnlgroup][index + (rf ? 8 : 0)] &
+                                       (0x7f << (i * 8))) >> (i * 8));
+
+                               if (rtlphy->current_chan_bw ==
+                                   HT_CHANNEL_WIDTH_20_40) {
+                                       if (pwr_diff_limit[i] >
+                                           rtlefuse->
+                                           pwrgroup_ht40[rf][channel - 1])
+                                               pwr_diff_limit[i] =
+                                                   rtlefuse->pwrgroup_ht40[rf]
+                                                   [channel - 1];
+                               } else {
+                                       if (pwr_diff_limit[i] >
+                                           rtlefuse->
+                                           pwrgroup_ht20[rf][channel - 1])
+                                               pwr_diff_limit[i] =
+                                                   rtlefuse->pwrgroup_ht20[rf]
+                                                   [channel - 1];
+                               }
+                       }
+
+                       customer_limit = (pwr_diff_limit[3] << 24) |
+                           (pwr_diff_limit[2] << 16) |
+                           (pwr_diff_limit[1] << 8) | (pwr_diff_limit[0]);
+
+                       RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                               "Customer's limit rf(%c) = 0x%x\n",
+                               ((rf == 0) ? 'A' : 'B'), customer_limit);
+
+                       writeVal = customer_limit +
+                           ((index < 2) ? powerBase0[rf] : powerBase1[rf]);
+
+                       RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                               "Customer, writeVal rf(%c)= 0x%x\n",
+                               ((rf == 0) ? 'A' : 'B'), writeVal);
+                       break;
+               default:
+                       chnlgroup = 0;
+                       writeVal = rtlphy->mcs_offset[chnlgroup][index +
+                           (rf ? 8 : 0)] + ((index < 2) ? powerBase0[rf] :
+                           powerBase1[rf]);
+
+                       RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                               "RTK better performance, writeVal rf(%c) = 0x%x\n",
+                               ((rf == 0) ? 'A' : 'B'), writeVal);
+                       break;
+               }
+
+               if (rtlpriv->dm.dynamic_txhighpower_lvl == TXHIGHPWRLEVEL_BT1)
+                       writeVal = writeVal - 0x06060606;
+               else if (rtlpriv->dm.dynamic_txhighpower_lvl ==
+                        TXHIGHPWRLEVEL_BT2)
+                       writeVal = writeVal - 0x0c0c0c0c;
+               *(p_outwriteval + rf) = writeVal;
+       }
+}
+
+static void _rtl8723ae_write_ofdm_power_reg(struct ieee80211_hw *hw,
+                                           u8 index, u32 *pValue)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       u16 regoffset_a[6] = {
+               RTXAGC_A_RATE18_06, RTXAGC_A_RATE54_24,
+               RTXAGC_A_MCS03_MCS00, RTXAGC_A_MCS07_MCS04,
+               RTXAGC_A_MCS11_MCS08, RTXAGC_A_MCS15_MCS12
+       };
+       u16 regoffset_b[6] = {
+               RTXAGC_B_RATE18_06, RTXAGC_B_RATE54_24,
+               RTXAGC_B_MCS03_MCS00, RTXAGC_B_MCS07_MCS04,
+               RTXAGC_B_MCS11_MCS08, RTXAGC_B_MCS15_MCS12
+       };
+       u8 i, rf, pwr_val[4];
+       u32 writeVal;
+       u16 regoffset;
+
+       for (rf = 0; rf < 2; rf++) {
+               writeVal = pValue[rf];
+               for (i = 0; i < 4; i++) {
+                       pwr_val[i] = (u8) ((writeVal & (0x7f <<
+                                                       (i * 8))) >> (i * 8));
+
+                       if (pwr_val[i] > RF6052_MAX_TX_PWR)
+                               pwr_val[i] = RF6052_MAX_TX_PWR;
+               }
+               writeVal = (pwr_val[3] << 24) | (pwr_val[2] << 16) |
+                   (pwr_val[1] << 8) | pwr_val[0];
+
+               if (rf == 0)
+                       regoffset = regoffset_a[index];
+               else
+                       regoffset = regoffset_b[index];
+               rtl_set_bbreg(hw, regoffset, MASKDWORD, writeVal);
+
+               RTPRINT(rtlpriv, FPHY, PHY_TXPWR,
+                       "Set 0x%x = %08x\n", regoffset, writeVal);
+
+               if (((get_rf_type(rtlphy) == RF_2T2R) &&
+                    (regoffset == RTXAGC_A_MCS15_MCS12 ||
+                     regoffset == RTXAGC_B_MCS15_MCS12)) ||
+                   ((get_rf_type(rtlphy) != RF_2T2R) &&
+                    (regoffset == RTXAGC_A_MCS07_MCS04 ||
+                     regoffset == RTXAGC_B_MCS07_MCS04))) {
+
+                       writeVal = pwr_val[3];
+                       if (regoffset == RTXAGC_A_MCS15_MCS12 ||
+                           regoffset == RTXAGC_A_MCS07_MCS04)
+                               regoffset = 0xc90;
+                       if (regoffset == RTXAGC_B_MCS15_MCS12 ||
+                           regoffset == RTXAGC_B_MCS07_MCS04)
+                               regoffset = 0xc98;
+
+                       for (i = 0; i < 3; i++) {
+                               writeVal = (writeVal > 6) ? (writeVal - 6) : 0;
+                               rtl_write_byte(rtlpriv, (u32) (regoffset + i),
+                                              (u8) writeVal);
+                       }
+               }
+       }
+}
+
+void rtl8723ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+                                          u8 *ppowerlevel, u8 channel)
+{
+       u32 writeVal[2], powerBase0[2], powerBase1[2];
+       u8 index;
+
+       rtl8723ae_phy_get_power_base(hw, ppowerlevel,
+                                 channel, &powerBase0[0], &powerBase1[0]);
+
+       for (index = 0; index < 6; index++) {
+               rtl8723ae_get_txpwr_val_by_reg(hw, channel, index,
+                                             &powerBase0[0],
+                                             &powerBase1[0],
+                                             &writeVal[0]);
+
+               _rtl8723ae_write_ofdm_power_reg(hw, index, &writeVal[0]);
+       }
+}
+
+static bool _rtl8723ae_phy_rf6052_config_parafile(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u32 u4_regvalue = 0;
+       u8 rfpath;
+       bool rtstatus = true;
+       struct bb_reg_def *pphyreg;
+
+       for (rfpath = 0; rfpath < rtlphy->num_total_rfpath; rfpath++) {
+
+               pphyreg = &rtlphy->phyreg_def[rfpath];
+
+               switch (rfpath) {
+               case RF90_PATH_A:
+               case RF90_PATH_C:
+                       u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+                                                   BRFSI_RFENV);
+                       break;
+               case RF90_PATH_B:
+               case RF90_PATH_D:
+                       u4_regvalue = rtl_get_bbreg(hw, pphyreg->rfintfs,
+                                                   BRFSI_RFENV << 16);
+                       break;
+               }
+
+               rtl_set_bbreg(hw, pphyreg->rfintfe, BRFSI_RFENV << 16, 0x1);
+               udelay(1);
+
+               rtl_set_bbreg(hw, pphyreg->rfintfo, BRFSI_RFENV, 0x1);
+               udelay(1);
+
+               rtl_set_bbreg(hw, pphyreg->rfhssi_para2,
+                             B3WIREADDREAALENGTH, 0x0);
+               udelay(1);
+
+               rtl_set_bbreg(hw, pphyreg->rfhssi_para2, B3WIREDATALENGTH, 0x0);
+               udelay(1);
+
+               switch (rfpath) {
+               case RF90_PATH_A:
+                       rtstatus = rtl8723ae_phy_config_rf_with_headerfile(hw,
+                                               (enum radio_path)rfpath);
+                       break;
+               case RF90_PATH_B:
+                       rtstatus = rtl8723ae_phy_config_rf_with_headerfile(hw,
+                                               (enum radio_path)rfpath);
+                       break;
+               case RF90_PATH_C:
+                       break;
+               case RF90_PATH_D:
+                       break;
+               }
+               switch (rfpath) {
+               case RF90_PATH_A:
+               case RF90_PATH_C:
+                       rtl_set_bbreg(hw, pphyreg->rfintfs,
+                                     BRFSI_RFENV, u4_regvalue);
+                       break;
+               case RF90_PATH_B:
+               case RF90_PATH_D:
+                       rtl_set_bbreg(hw, pphyreg->rfintfs,
+                                     BRFSI_RFENV << 16, u4_regvalue);
+                       break;
+               }
+               if (rtstatus != true) {
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
+                                "Radio[%d] Fail!!", rfpath);
+                       return false;
+               }
+       }
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "<---\n");
+       return rtstatus;
+}
+
+bool rtl8723ae_phy_rf6052_config(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+
+       if (rtlphy->rf_type == RF_1T1R)
+               rtlphy->num_total_rfpath = 1;
+       else
+               rtlphy->num_total_rfpath = 2;
+
+       return _rtl8723ae_phy_rf6052_config_parafile(hw);
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/rf.h b/drivers/net/wireless/rtlwifi/rtl8723ae/rf.h
new file mode 100644 (file)
index 0000000..d0f9dd7
--- /dev/null
@@ -0,0 +1,43 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_RF_H__
+#define __RTL8723E_RF_H__
+
+#define RF6052_MAX_TX_PWR              0x3F
+
+extern void rtl8723ae_phy_rf6052_set_bandwidth(struct ieee80211_hw *hw,
+                                           u8 bandwidth);
+extern void rtl8723ae_phy_rf6052_set_cck_txpower(struct ieee80211_hw *hw,
+                                             u8 *ppowerlevel);
+extern void rtl8723ae_phy_rf6052_set_ofdm_txpower(struct ieee80211_hw *hw,
+                                              u8 *ppowerlevel, u8 channel);
+extern bool rtl8723ae_phy_rf6052_config(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.c
new file mode 100644 (file)
index 0000000..0afdc24
--- /dev/null
@@ -0,0 +1,387 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include <linux/vmalloc.h>
+#include <linux/module.h>
+
+#include "../core.h"
+#include "../pci.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "dm.h"
+#include "hw.h"
+#include "sw.h"
+#include "trx.h"
+#include "led.h"
+#include "table.h"
+#include "hal_btc.h"
+
+static void rtl8723ae_init_aspm_vars(struct ieee80211_hw *hw)
+{
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+
+       /*close ASPM for AMD defaultly */
+       rtlpci->const_amdpci_aspm = 0;
+
+       /* ASPM PS mode.
+        * 0 - Disable ASPM,
+        * 1 - Enable ASPM without Clock Req,
+        * 2 - Enable ASPM with Clock Req,
+        * 3 - Alwyas Enable ASPM with Clock Req,
+        * 4 - Always Enable ASPM without Clock Req.
+        * set defult to RTL8192CE:3 RTL8192E:2
+        */
+       rtlpci->const_pci_aspm = 3;
+
+       /*Setting for PCI-E device */
+       rtlpci->const_devicepci_aspm_setting = 0x03;
+
+       /*Setting for PCI-E bridge */
+       rtlpci->const_hostpci_aspm_setting = 0x02;
+
+       /* In Hw/Sw Radio Off situation.
+        * 0 - Default,
+        * 1 - From ASPM setting without low Mac Pwr,
+        * 2 - From ASPM setting with low Mac Pwr,
+        * 3 - Bus D3
+        * set default to RTL8192CE:0 RTL8192SE:2
+        */
+       rtlpci->const_hwsw_rfoff_d3 = 0;
+
+       /* This setting works for those device with
+        * backdoor ASPM setting such as EPHY setting.
+        * 0 - Not support ASPM,
+        * 1 - Support ASPM,
+        * 2 - According to chipset.
+        */
+       rtlpci->const_support_pciaspm = 1;
+}
+
+int rtl8723ae_init_sw_vars(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       int err;
+
+       rtl8723ae_bt_reg_init(hw);
+       rtlpriv->dm.dm_initialgain_enable = 1;
+       rtlpriv->dm.dm_flag = 0;
+       rtlpriv->dm.disable_framebursting = 0;
+       rtlpriv->dm.thermalvalue = 0;
+       rtlpci->transmit_config = CFENDFORM | BIT(12) | BIT(13);
+
+       /* compatible 5G band 88ce just 2.4G band & smsp */
+       rtlpriv->rtlhal.current_bandtype = BAND_ON_2_4G;
+       rtlpriv->rtlhal.bandset = BAND_ON_2_4G;
+       rtlpriv->rtlhal.macphymode = SINGLEMAC_SINGLEPHY;
+
+       rtlpci->receive_config = (RCR_APPFCS |
+                                 RCR_APP_MIC |
+                                 RCR_APP_ICV |
+                                 RCR_APP_PHYST_RXFF |
+                                 RCR_HTC_LOC_CTRL |
+                                 RCR_AMF |
+                                 RCR_ACF |
+                                 RCR_ADF |
+                                 RCR_AICV |
+                                 RCR_AB |
+                                 RCR_AM |
+                                 RCR_APM |
+                                 0);
+
+       rtlpci->irq_mask[0] =
+           (u32) (PHIMR_ROK |
+                  PHIMR_RDU |
+                  PHIMR_VODOK |
+                  PHIMR_VIDOK |
+                  PHIMR_BEDOK |
+                  PHIMR_BKDOK |
+                  PHIMR_MGNTDOK |
+                  PHIMR_HIGHDOK |
+                  PHIMR_C2HCMD |
+                  PHIMR_HISRE_IND |
+                  PHIMR_TSF_BIT32_TOGGLE |
+                  PHIMR_TXBCNOK |
+                  PHIMR_PSTIMEOUT |
+                  0);
+
+       rtlpci->irq_mask[1] = (u32)(PHIMR_RXFOVW | 0);
+
+       /* for debug level */
+       rtlpriv->dbg.global_debuglevel = rtlpriv->cfg->mod_params->debug;
+       /* for LPS & IPS */
+       rtlpriv->psc.inactiveps = rtlpriv->cfg->mod_params->inactiveps;
+       rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps;
+       rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps;
+       rtlpriv->psc.reg_fwctrl_lps = 3;
+       rtlpriv->psc.reg_max_lps_awakeintvl = 5;
+       /* for ASPM, you can close aspm through
+        * set const_support_pciaspm = 0
+        */
+       rtl8723ae_init_aspm_vars(hw);
+
+       if (rtlpriv->psc.reg_fwctrl_lps == 1)
+               rtlpriv->psc.fwctrl_psmode = FW_PS_MIN_MODE;
+       else if (rtlpriv->psc.reg_fwctrl_lps == 2)
+               rtlpriv->psc.fwctrl_psmode = FW_PS_MAX_MODE;
+       else if (rtlpriv->psc.reg_fwctrl_lps == 3)
+               rtlpriv->psc.fwctrl_psmode = FW_PS_DTIM_MODE;
+
+       /* for firmware buf */
+       rtlpriv->rtlhal.pfirmware = vmalloc(0x6000);
+       if (!rtlpriv->rtlhal.pfirmware) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Can't alloc buffer for fw.\n");
+               return 1;
+       }
+
+       if (IS_VENDOR_8723_A_CUT(rtlhal->version))
+               rtlpriv->cfg->fw_name = "rtlwifi/rtl8723fw.bin";
+       else if (IS_81xxC_VENDOR_UMC_B_CUT(rtlhal->version))
+               rtlpriv->cfg->fw_name = "rtlwifi/rtl8723fw_B.bin";
+
+       rtlpriv->max_fw_size = 0x6000;
+       pr_info("Using firmware %s\n", rtlpriv->cfg->fw_name);
+       err = request_firmware_nowait(THIS_MODULE, 1, rtlpriv->cfg->fw_name,
+                                     rtlpriv->io.dev, GFP_KERNEL, hw,
+                                     rtl_fw_cb);
+       if (err) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
+                        "Failed to request firmware!\n");
+               return 1;
+       }
+       return 0;
+}
+
+void rtl8723ae_deinit_sw_vars(struct ieee80211_hw *hw)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       if (rtlpriv->rtlhal.pfirmware) {
+               vfree(rtlpriv->rtlhal.pfirmware);
+               rtlpriv->rtlhal.pfirmware = NULL;
+       }
+}
+
+static struct rtl_hal_ops rtl8723ae_hal_ops = {
+       .init_sw_vars = rtl8723ae_init_sw_vars,
+       .deinit_sw_vars = rtl8723ae_deinit_sw_vars,
+       .read_eeprom_info = rtl8723ae_read_eeprom_info,
+       .interrupt_recognized = rtl8723ae_interrupt_recognized,
+       .hw_init = rtl8723ae_hw_init,
+       .hw_disable = rtl8723ae_card_disable,
+       .hw_suspend = rtl8723ae_suspend,
+       .hw_resume = rtl8723ae_resume,
+       .enable_interrupt = rtl8723ae_enable_interrupt,
+       .disable_interrupt = rtl8723ae_disable_interrupt,
+       .set_network_type = rtl8723ae_set_network_type,
+       .set_chk_bssid = rtl8723ae_set_check_bssid,
+       .set_qos = rtl8723ae_set_qos,
+       .set_bcn_reg = rtl8723ae_set_beacon_related_registers,
+       .set_bcn_intv = rtl8723ae_set_beacon_interval,
+       .update_interrupt_mask = rtl8723ae_update_interrupt_mask,
+       .get_hw_reg = rtl8723ae_get_hw_reg,
+       .set_hw_reg = rtl8723ae_set_hw_reg,
+       .update_rate_tbl = rtl8723ae_update_hal_rate_tbl,
+       .fill_tx_desc = rtl8723ae_tx_fill_desc,
+       .fill_tx_cmddesc = rtl8723ae_tx_fill_cmddesc,
+       .query_rx_desc = rtl8723ae_rx_query_desc,
+       .set_channel_access = rtl8723ae_update_channel_access_setting,
+       .radio_onoff_checking = rtl8723ae_gpio_radio_on_off_checking,
+       .set_bw_mode = rtl8723ae_phy_set_bw_mode,
+       .switch_channel = rtl8723ae_phy_sw_chnl,
+       .dm_watchdog = rtl8723ae_dm_watchdog,
+       .scan_operation_backup = rtl8723ae_phy_scan_operation_backup,
+       .set_rf_power_state = rtl8723ae_phy_set_rf_power_state,
+       .led_control = rtl8723ae_led_control,
+       .set_desc = rtl8723ae_set_desc,
+       .get_desc = rtl8723ae_get_desc,
+       .tx_polling = rtl8723ae_tx_polling,
+       .enable_hw_sec = rtl8723ae_enable_hw_security_config,
+       .set_key = rtl8723ae_set_key,
+       .init_sw_leds = rtl8723ae_init_sw_leds,
+       .allow_all_destaddr = rtl8723ae_allow_all_destaddr,
+       .get_bbreg = rtl8723ae_phy_query_bb_reg,
+       .set_bbreg = rtl8723ae_phy_set_bb_reg,
+       .get_rfreg = rtl8723ae_phy_query_rf_reg,
+       .set_rfreg = rtl8723ae_phy_set_rf_reg,
+       .c2h_command_handle = rtl_8723e_c2h_command_handle,
+       .bt_wifi_media_status_notify = rtl_8723e_bt_wifi_media_status_notify,
+       .bt_coex_off_before_lps = rtl8723ae_bt_coex_off_before_lps,
+};
+
+static struct rtl_mod_params rtl8723ae_mod_params = {
+       .sw_crypto = false,
+       .inactiveps = true,
+       .swctrl_lps = false,
+       .fwctrl_lps = true,
+       .debug = DBG_EMERG,
+};
+
+static struct rtl_hal_cfg rtl8723ae_hal_cfg = {
+       .bar_id = 2,
+       .write_readback = true,
+       .name = "rtl8723ae_pci",
+       .fw_name = "rtlwifi/rtl8723aefw.bin",
+       .ops = &rtl8723ae_hal_ops,
+       .mod_params = &rtl8723ae_mod_params,
+       .maps[SYS_ISO_CTRL] = REG_SYS_ISO_CTRL,
+       .maps[SYS_FUNC_EN] = REG_SYS_FUNC_EN,
+       .maps[SYS_CLK] = REG_SYS_CLKR,
+       .maps[MAC_RCR_AM] = AM,
+       .maps[MAC_RCR_AB] = AB,
+       .maps[MAC_RCR_ACRC32] = ACRC32,
+       .maps[MAC_RCR_ACF] = ACF,
+       .maps[MAC_RCR_AAP] = AAP,
+       .maps[EFUSE_TEST] = REG_EFUSE_TEST,
+       .maps[EFUSE_CTRL] = REG_EFUSE_CTRL,
+       .maps[EFUSE_CLK] = 0,
+       .maps[EFUSE_CLK_CTRL] = REG_EFUSE_CTRL,
+       .maps[EFUSE_PWC_EV12V] = PWC_EV12V,
+       .maps[EFUSE_FEN_ELDR] = FEN_ELDR,
+       .maps[EFUSE_LOADER_CLK_EN] = LOADER_CLK_EN,
+       .maps[EFUSE_ANA8M] = ANA8M,
+       .maps[EFUSE_HWSET_MAX_SIZE] = HWSET_MAX_SIZE,
+       .maps[EFUSE_MAX_SECTION_MAP] = EFUSE_MAX_SECTION,
+       .maps[EFUSE_REAL_CONTENT_SIZE] = EFUSE_REAL_CONTENT_LEN,
+       .maps[EFUSE_OOB_PROTECT_BYTES_LEN] = EFUSE_OOB_PROTECT_BYTES,
+
+       .maps[RWCAM] = REG_CAMCMD,
+       .maps[WCAMI] = REG_CAMWRITE,
+       .maps[RCAMO] = REG_CAMREAD,
+       .maps[CAMDBG] = REG_CAMDBG,
+       .maps[SECR] = REG_SECCFG,
+       .maps[SEC_CAM_NONE] = CAM_NONE,
+       .maps[SEC_CAM_WEP40] = CAM_WEP40,
+       .maps[SEC_CAM_TKIP] = CAM_TKIP,
+       .maps[SEC_CAM_AES] = CAM_AES,
+       .maps[SEC_CAM_WEP104] = CAM_WEP104,
+
+       .maps[RTL_IMR_BCNDMAINT6] = IMR_BCNDMAINT6,
+       .maps[RTL_IMR_BCNDMAINT5] = IMR_BCNDMAINT5,
+       .maps[RTL_IMR_BCNDMAINT4] = IMR_BCNDMAINT4,
+       .maps[RTL_IMR_BCNDMAINT3] = IMR_BCNDMAINT3,
+       .maps[RTL_IMR_BCNDMAINT2] = IMR_BCNDMAINT2,
+       .maps[RTL_IMR_BCNDMAINT1] = IMR_BCNDMAINT1,
+       .maps[RTL_IMR_BCNDOK8] = IMR_BCNDOK8,
+       .maps[RTL_IMR_BCNDOK7] = IMR_BCNDOK7,
+       .maps[RTL_IMR_BCNDOK6] = IMR_BCNDOK6,
+       .maps[RTL_IMR_BCNDOK5] = IMR_BCNDOK5,
+       .maps[RTL_IMR_BCNDOK4] = IMR_BCNDOK4,
+       .maps[RTL_IMR_BCNDOK3] = IMR_BCNDOK3,
+       .maps[RTL_IMR_BCNDOK2] = IMR_BCNDOK2,
+       .maps[RTL_IMR_BCNDOK1] = IMR_BCNDOK1,
+       .maps[RTL_IMR_TIMEOUT2] = IMR_TIMEOUT2,
+       .maps[RTL_IMR_TIMEOUT1] = IMR_TIMEOUT1,
+
+       .maps[RTL_IMR_TXFOVW] = PHIMR_TXFOVW,
+       .maps[RTL_IMR_PSTIMEOUT] = PHIMR_PSTIMEOUT,
+       .maps[RTL_IMR_BcnInt] = PHIMR_BCNDMAINT0,
+       .maps[RTL_IMR_RXFOVW] = PHIMR_RXFOVW,
+       .maps[RTL_IMR_RDU] = PHIMR_RDU,
+       .maps[RTL_IMR_ATIMEND] = PHIMR_ATIMEND_E,
+       .maps[RTL_IMR_BDOK] = PHIMR_BCNDOK0,
+       .maps[RTL_IMR_MGNTDOK] = PHIMR_MGNTDOK,
+       .maps[RTL_IMR_TBDER] = PHIMR_TXBCNERR,
+       .maps[RTL_IMR_HIGHDOK] = PHIMR_HIGHDOK,
+       .maps[RTL_IMR_TBDOK] = PHIMR_TXBCNOK,
+       .maps[RTL_IMR_BKDOK] = PHIMR_BKDOK,
+       .maps[RTL_IMR_BEDOK] = PHIMR_BEDOK,
+       .maps[RTL_IMR_VIDOK] = PHIMR_VIDOK,
+       .maps[RTL_IMR_VODOK] = PHIMR_VODOK,
+       .maps[RTL_IMR_ROK] = PHIMR_ROK,
+       .maps[RTL_IBSS_INT_MASKS] = (PHIMR_BCNDMAINT0 |
+                                    PHIMR_TXBCNOK | PHIMR_TXBCNERR),
+       .maps[RTL_IMR_C2HCMD] = PHIMR_C2HCMD,
+
+
+       .maps[RTL_RC_CCK_RATE1M] = DESC92_RATE1M,
+       .maps[RTL_RC_CCK_RATE2M] = DESC92_RATE2M,
+       .maps[RTL_RC_CCK_RATE5_5M] = DESC92_RATE5_5M,
+       .maps[RTL_RC_CCK_RATE11M] = DESC92_RATE11M,
+       .maps[RTL_RC_OFDM_RATE6M] = DESC92_RATE6M,
+       .maps[RTL_RC_OFDM_RATE9M] = DESC92_RATE9M,
+       .maps[RTL_RC_OFDM_RATE12M] = DESC92_RATE12M,
+       .maps[RTL_RC_OFDM_RATE18M] = DESC92_RATE18M,
+       .maps[RTL_RC_OFDM_RATE24M] = DESC92_RATE24M,
+       .maps[RTL_RC_OFDM_RATE36M] = DESC92_RATE36M,
+       .maps[RTL_RC_OFDM_RATE48M] = DESC92_RATE48M,
+       .maps[RTL_RC_OFDM_RATE54M] = DESC92_RATE54M,
+
+       .maps[RTL_RC_HT_RATEMCS7] = DESC92_RATEMCS7,
+       .maps[RTL_RC_HT_RATEMCS15] = DESC92_RATEMCS15,
+};
+
+static struct pci_device_id rtl8723ae_pci_ids[] __devinitdata = {
+       {RTL_PCI_DEVICE(PCI_VENDOR_ID_REALTEK, 0x8723, rtl8723ae_hal_cfg)},
+       {},
+};
+
+MODULE_DEVICE_TABLE(pci, rtl8723ae_pci_ids);
+
+MODULE_AUTHOR("lizhaoming      <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger    <Larry.Finger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("Realtek 8723E 802.11n PCI wireless");
+MODULE_FIRMWARE("rtlwifi/rtl8723aefw.bin");
+MODULE_FIRMWARE("rtlwifi/rtl8723aefw_B.bin");
+
+module_param_named(swenc, rtl8723ae_mod_params.sw_crypto, bool, 0444);
+module_param_named(debug, rtl8723ae_mod_params.debug, int, 0444);
+module_param_named(ips, rtl8723ae_mod_params.inactiveps, bool, 0444);
+module_param_named(swlps, rtl8723ae_mod_params.swctrl_lps, bool, 0444);
+module_param_named(fwlps, rtl8723ae_mod_params.fwctrl_lps, bool, 0444);
+MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n");
+MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n");
+MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n");
+MODULE_PARM_DESC(fwlps, "Set to 1 to use FW control power save (default 1)\n");
+MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)");
+
+static const struct dev_pm_ops rtlwifi_pm_ops = {
+       .suspend = rtl_pci_suspend,
+       .resume = rtl_pci_resume,
+       .freeze = rtl_pci_suspend,
+       .thaw = rtl_pci_resume,
+       .poweroff = rtl_pci_suspend,
+       .restore = rtl_pci_resume,
+};
+
+static struct pci_driver rtl8723ae_driver = {
+       .name = KBUILD_MODNAME,
+       .id_table = rtl8723ae_pci_ids,
+       .probe = rtl_pci_probe,
+       .remove = rtl_pci_disconnect,
+       .driver.pm = &rtlwifi_pm_ops,
+};
+
+module_pci_driver(rtl8723ae_driver);
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/sw.h b/drivers/net/wireless/rtlwifi/rtl8723ae/sw.h
new file mode 100644 (file)
index 0000000..fc4fde5
--- /dev/null
@@ -0,0 +1,37 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_SW_H__
+#define __RTL8723E_SW_H__
+
+int rtl8723ae_init_sw_vars(struct ieee80211_hw *hw);
+void rtl8723ae_deinit_sw_vars(struct ieee80211_hw *hw);
+void rtl8723ae_init_var_map(struct ieee80211_hw *hw);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/table.c b/drivers/net/wireless/rtlwifi/rtl8723ae/table.c
new file mode 100644 (file)
index 0000000..9b0b50c
--- /dev/null
@@ -0,0 +1,738 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on  2010/ 5/18,  1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "table.h"
+
+u32 RTL8723EPHY_REG_1TARRAY[RTL8723E_PHY_REG_1TARRAY_LENGTH] = {
+       0x800, 0x80040000,
+       0x804, 0x00000003,
+       0x808, 0x0000fc00,
+       0x80c, 0x0000000a,
+       0x810, 0x10005388,
+       0x814, 0x020c3d10,
+       0x818, 0x02200385,
+       0x81c, 0x00000000,
+       0x820, 0x01000100,
+       0x824, 0x00390004,
+       0x828, 0x00000000,
+       0x82c, 0x00000000,
+       0x830, 0x00000000,
+       0x834, 0x00000000,
+       0x838, 0x00000000,
+       0x83c, 0x00000000,
+       0x840, 0x00010000,
+       0x844, 0x00000000,
+       0x848, 0x00000000,
+       0x84c, 0x00000000,
+       0x850, 0x00000000,
+       0x854, 0x00000000,
+       0x858, 0x569a569a,
+       0x85c, 0x001b25a4,
+       0x860, 0x66f60110,
+       0x864, 0x061f0130,
+       0x868, 0x00000000,
+       0x86c, 0x32323200,
+       0x870, 0x07000760,
+       0x874, 0x22004000,
+       0x878, 0x00000808,
+       0x87c, 0x00000000,
+       0x880, 0xc0083070,
+       0x884, 0x000004d5,
+       0x888, 0x00000000,
+       0x88c, 0xccc000c0,
+       0x890, 0x00000800,
+       0x894, 0xfffffffe,
+       0x898, 0x40302010,
+       0x89c, 0x00706050,
+       0x900, 0x00000000,
+       0x904, 0x00000023,
+       0x908, 0x00000000,
+       0x90c, 0x81121111,
+       0xa00, 0x00d047c8,
+       0xa04, 0x80ff000c,
+       0xa08, 0x8c838300,
+       0xa0c, 0x2e68120f,
+       0xa10, 0x9500bb78,
+       0xa14, 0x11144028,
+       0xa18, 0x00881117,
+       0xa1c, 0x89140f00,
+       0xa20, 0x1a1b0000,
+       0xa24, 0x090e1317,
+       0xa28, 0x00000204,
+       0xa2c, 0x00d30000,
+       0xa70, 0x101fbf00,
+       0xa74, 0x00000007,
+       0xa78, 0x00000900,
+       0xc00, 0x48071d40,
+       0xc04, 0x03a05611,
+       0xc08, 0x000000e4,
+       0xc0c, 0x6c6c6c6c,
+       0xc10, 0x08800000,
+       0xc14, 0x40000100,
+       0xc18, 0x08800000,
+       0xc1c, 0x40000100,
+       0xc20, 0x00000000,
+       0xc24, 0x00000000,
+       0xc28, 0x00000000,
+       0xc2c, 0x00000000,
+       0xc30, 0x69e9ac44,
+       0xc34, 0x469652cf,
+       0xc38, 0x49795994,
+       0xc3c, 0x0a97971c,
+       0xc40, 0x1f7c403f,
+       0xc44, 0x000100b7,
+       0xc48, 0xec020107,
+       0xc4c, 0x007f037f,
+       0xc50, 0x69543420,
+       0xc54, 0x43bc0094,
+       0xc58, 0x69543420,
+       0xc5c, 0x433c0094,
+       0xc60, 0x00000000,
+       0xc64, 0x7116848b,
+       0xc68, 0x47c00bff,
+       0xc6c, 0x00000036,
+       0xc70, 0x2c7f000d,
+       0xc74, 0x018610db,
+       0xc78, 0x0000001f,
+       0xc7c, 0x00b91612,
+       0xc80, 0x40000100,
+       0xc84, 0x20f60000,
+       0xc88, 0x40000100,
+       0xc8c, 0x20200000,
+       0xc90, 0x00121820,
+       0xc94, 0x00000000,
+       0xc98, 0x00121820,
+       0xc9c, 0x00007f7f,
+       0xca0, 0x00000000,
+       0xca4, 0x00000080,
+       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, 0x00000000,
+       0xce8, 0x37644302,
+       0xcec, 0x2f97d40c,
+       0xd00, 0x00080740,
+       0xd04, 0x00020401,
+       0xd08, 0x0000907f,
+       0xd0c, 0x20010201,
+       0xd10, 0xa0633333,
+       0xd14, 0x3333bc43,
+       0xd18, 0x7a8f5b6b,
+       0xd2c, 0xcc979975,
+       0xd30, 0x00000000,
+       0xd34, 0x80608000,
+       0xd38, 0x00000000,
+       0xd3c, 0x00027293,
+       0xd40, 0x00000000,
+       0xd44, 0x00000000,
+       0xd48, 0x00000000,
+       0xd4c, 0x00000000,
+       0xd50, 0x6437140a,
+       0xd54, 0x00000000,
+       0xd58, 0x00000000,
+       0xd5c, 0x30032064,
+       0xd60, 0x4653de68,
+       0xd64, 0x04518a3c,
+       0xd68, 0x00002101,
+       0xd6c, 0x2a201c16,
+       0xd70, 0x1812362e,
+       0xd74, 0x322c2220,
+       0xd78, 0x000e3c24,
+       0xe00, 0x2a2a2a2a,
+       0xe04, 0x2a2a2a2a,
+       0xe08, 0x03902a2a,
+       0xe10, 0x2a2a2a2a,
+       0xe14, 0x2a2a2a2a,
+       0xe18, 0x2a2a2a2a,
+       0xe1c, 0x2a2a2a2a,
+       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, 0x001b25a4,
+       0xe6c, 0x631b25a0,
+       0xe70, 0x631b25a0,
+       0xe74, 0x081b25a0,
+       0xe78, 0x081b25a0,
+       0xe7c, 0x081b25a0,
+       0xe80, 0x081b25a0,
+       0xe84, 0x631b25a0,
+       0xe88, 0x081b25a0,
+       0xe8c, 0x631b25a0,
+       0xed0, 0x631b25a0,
+       0xed4, 0x631b25a0,
+       0xed8, 0x631b25a0,
+       0xedc, 0x001b25a0,
+       0xee0, 0x001b25a0,
+       0xeec, 0x6b1b25a0,
+       0xf14, 0x00000003,
+       0xf4c, 0x00000000,
+       0xf00, 0x00000300,
+};
+
+u32 RTL8723EPHY_REG_ARRAY_PG[RTL8723E_PHY_REG_ARRAY_PGLENGTH] = {
+       0xe00, 0xffffffff, 0x0a0c0c0c,
+       0xe04, 0xffffffff, 0x02040608,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x0a0c0d0e,
+       0xe14, 0xffffffff, 0x02040608,
+       0xe18, 0xffffffff, 0x0a0c0d0e,
+       0xe1c, 0xffffffff, 0x02040608,
+       0x830, 0xffffffff, 0x0a0c0c0c,
+       0x834, 0xffffffff, 0x02040608,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x0a0c0d0e,
+       0x848, 0xffffffff, 0x02040608,
+       0x84c, 0xffffffff, 0x0a0c0d0e,
+       0x868, 0xffffffff, 0x02040608,
+       0xe00, 0xffffffff, 0x00000000,
+       0xe04, 0xffffffff, 0x00000000,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x00000000,
+       0x834, 0xffffffff, 0x00000000,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x04040404,
+       0xe04, 0xffffffff, 0x00020204,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x06060606,
+       0xe14, 0xffffffff, 0x00020406,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x04040404,
+       0x834, 0xffffffff, 0x00020204,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x06060606,
+       0x848, 0xffffffff, 0x00020406,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x00000000,
+       0xe04, 0xffffffff, 0x00000000,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x00000000,
+       0x834, 0xffffffff, 0x00000000,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x00000000,
+       0xe04, 0xffffffff, 0x00000000,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x00000000,
+       0x834, 0xffffffff, 0x00000000,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x04040404,
+       0xe04, 0xffffffff, 0x00020204,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x04040404,
+       0x834, 0xffffffff, 0x00020204,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+       0xe00, 0xffffffff, 0x00000000,
+       0xe04, 0xffffffff, 0x00000000,
+       0xe08, 0x0000ff00, 0x00000000,
+       0x86c, 0xffffff00, 0x00000000,
+       0xe10, 0xffffffff, 0x00000000,
+       0xe14, 0xffffffff, 0x00000000,
+       0xe18, 0xffffffff, 0x00000000,
+       0xe1c, 0xffffffff, 0x00000000,
+       0x830, 0xffffffff, 0x00000000,
+       0x834, 0xffffffff, 0x00000000,
+       0x838, 0xffffff00, 0x00000000,
+       0x86c, 0x000000ff, 0x00000000,
+       0x83c, 0xffffffff, 0x00000000,
+       0x848, 0xffffffff, 0x00000000,
+       0x84c, 0xffffffff, 0x00000000,
+       0x868, 0xffffffff, 0x00000000,
+};
+
+u32 RTL8723E_RADIOA_1TARRAY[Rtl8723ERADIOA_1TARRAYLENGTH] = {
+       0x000, 0x00030159,
+       0x001, 0x00031284,
+       0x002, 0x00098000,
+       0x003, 0x00018c63,
+       0x004, 0x000210e7,
+       0x009, 0x0002044f,
+       0x00a, 0x0001a3f1,
+       0x00b, 0x00014787,
+       0x00c, 0x000896fe,
+       0x00d, 0x0000e02c,
+       0x00e, 0x00039ce7,
+       0x00f, 0x00000451,
+       0x019, 0x00000000,
+       0x01a, 0x00030355,
+       0x01b, 0x00060a00,
+       0x01c, 0x000fc378,
+       0x01d, 0x000a1250,
+       0x01e, 0x0004445f,
+       0x01f, 0x00080001,
+       0x020, 0x0000b614,
+       0x021, 0x0006c000,
+       0x022, 0x00000000,
+       0x023, 0x00001558,
+       0x024, 0x00000060,
+       0x025, 0x00000483,
+       0x026, 0x0004f000,
+       0x027, 0x000ec7d9,
+       0x028, 0x00057730,
+       0x029, 0x00004783,
+       0x02a, 0x00000001,
+       0x02b, 0x00021334,
+       0x02a, 0x00000000,
+       0x02b, 0x00000054,
+       0x02a, 0x00000001,
+       0x02b, 0x00000808,
+       0x02b, 0x00053333,
+       0x02c, 0x0000000c,
+       0x02a, 0x00000002,
+       0x02b, 0x00000808,
+       0x02b, 0x0005b333,
+       0x02c, 0x0000000d,
+       0x02a, 0x00000003,
+       0x02b, 0x00000808,
+       0x02b, 0x00063333,
+       0x02c, 0x0000000d,
+       0x02a, 0x00000004,
+       0x02b, 0x00000808,
+       0x02b, 0x0006b333,
+       0x02c, 0x0000000d,
+       0x02a, 0x00000005,
+       0x02b, 0x00000808,
+       0x02b, 0x00073333,
+       0x02c, 0x0000000d,
+       0x02a, 0x00000006,
+       0x02b, 0x00000709,
+       0x02b, 0x0005b333,
+       0x02c, 0x0000000d,
+       0x02a, 0x00000007,
+       0x02b, 0x00000709,
+       0x02b, 0x00063333,
+       0x02c, 0x0000000d,
+       0x02a, 0x00000008,
+       0x02b, 0x0000060a,
+       0x02b, 0x0004b333,
+       0x02c, 0x0000000d,
+       0x02a, 0x00000009,
+       0x02b, 0x0000060a,
+       0x02b, 0x00053333,
+       0x02c, 0x0000000d,
+       0x02a, 0x0000000a,
+       0x02b, 0x0000060a,
+       0x02b, 0x0005b333,
+       0x02c, 0x0000000d,
+       0x02a, 0x0000000b,
+       0x02b, 0x0000060a,
+       0x02b, 0x00063333,
+       0x02c, 0x0000000d,
+       0x02a, 0x0000000c,
+       0x02b, 0x0000060a,
+       0x02b, 0x0006b333,
+       0x02c, 0x0000000d,
+       0x02a, 0x0000000d,
+       0x02b, 0x0000060a,
+       0x02b, 0x00073333,
+       0x02c, 0x0000000d,
+       0x02a, 0x0000000e,
+       0x02b, 0x0000050b,
+       0x02b, 0x00066666,
+       0x02c, 0x0000001a,
+       0x02a, 0x000e0000,
+       0x010, 0x0004000f,
+       0x011, 0x000e31fc,
+       0x010, 0x0006000f,
+       0x011, 0x000ff9f8,
+       0x010, 0x0002000f,
+       0x011, 0x000203f9,
+       0x010, 0x0003000f,
+       0x011, 0x000ff500,
+       0x010, 0x00000000,
+       0x011, 0x00000000,
+       0x010, 0x0008000f,
+       0x011, 0x0003f100,
+       0x010, 0x0009000f,
+       0x011, 0x00023100,
+       0x012, 0x00032000,
+       0x012, 0x00071000,
+       0x012, 0x000b0000,
+       0x012, 0x000fc000,
+       0x013, 0x000287b3,
+       0x013, 0x000244b7,
+       0x013, 0x000204ab,
+       0x013, 0x0001c49f,
+       0x013, 0x00018493,
+       0x013, 0x0001429b,
+       0x013, 0x00010299,
+       0x013, 0x0000c29c,
+       0x013, 0x000081a0,
+       0x013, 0x000040ac,
+       0x013, 0x00000020,
+       0x014, 0x0001944c,
+       0x014, 0x00059444,
+       0x014, 0x0009944c,
+       0x014, 0x000d9444,
+       0x015, 0x0000f424,
+       0x015, 0x0004f407,
+       0x015, 0x0008f424,
+       0x015, 0x000cf424,
+       0x016, 0x00000339,
+       0x016, 0x00040339,
+       0x016, 0x00080339,
+       0x016, 0x000c0336,
+       0x000, 0x00010159,
+       0x018, 0x0000f401,
+       0x0fe, 0x00000000,
+       0x0fe, 0x00000000,
+       0x01f, 0x00080003,
+       0x0fe, 0x00000000,
+       0x0fe, 0x00000000,
+       0x01e, 0x00044457,
+       0x01f, 0x00080000,
+       0x000, 0x00030159,
+};
+
+
+u32 RTL8723E_RADIOB_1TARRAY[RTL8723E_RADIOB_1TARRAYLENGTH] = {
+       0x0,
+};
+
+
+u32 RTL8723EMAC_ARRAY[RTL8723E_MACARRAYLENGTH] = {
+       0x420, 0x00000080,
+       0x423, 0x00000000,
+       0x430, 0x00000000,
+       0x431, 0x00000000,
+       0x432, 0x00000000,
+       0x433, 0x00000001,
+       0x434, 0x00000004,
+       0x435, 0x00000005,
+       0x436, 0x00000006,
+       0x437, 0x00000007,
+       0x438, 0x00000000,
+       0x439, 0x00000000,
+       0x43a, 0x00000000,
+       0x43b, 0x00000001,
+       0x43c, 0x00000004,
+       0x43d, 0x00000005,
+       0x43e, 0x00000006,
+       0x43f, 0x00000007,
+       0x440, 0x0000005d,
+       0x441, 0x00000001,
+       0x442, 0x00000000,
+       0x444, 0x00000015,
+       0x445, 0x000000f0,
+       0x446, 0x0000000f,
+       0x447, 0x00000000,
+       0x458, 0x00000041,
+       0x459, 0x000000a8,
+       0x45a, 0x00000072,
+       0x45b, 0x000000b9,
+       0x460, 0x00000066,
+       0x461, 0x00000066,
+       0x462, 0x00000008,
+       0x463, 0x00000003,
+       0x4c8, 0x000000ff,
+       0x4c9, 0x00000008,
+       0x4cc, 0x000000ff,
+       0x4cd, 0x000000ff,
+       0x4ce, 0x00000001,
+       0x500, 0x00000026,
+       0x501, 0x000000a2,
+       0x502, 0x0000002f,
+       0x503, 0x00000000,
+       0x504, 0x00000028,
+       0x505, 0x000000a3,
+       0x506, 0x0000005e,
+       0x507, 0x00000000,
+       0x508, 0x0000002b,
+       0x509, 0x000000a4,
+       0x50a, 0x0000005e,
+       0x50b, 0x00000000,
+       0x50c, 0x0000004f,
+       0x50d, 0x000000a4,
+       0x50e, 0x00000000,
+       0x50f, 0x00000000,
+       0x512, 0x0000001c,
+       0x514, 0x0000000a,
+       0x515, 0x00000010,
+       0x516, 0x0000000a,
+       0x517, 0x00000010,
+       0x51a, 0x00000016,
+       0x524, 0x0000000f,
+       0x525, 0x0000004f,
+       0x546, 0x00000040,
+       0x547, 0x00000000,
+       0x550, 0x00000010,
+       0x551, 0x00000010,
+       0x559, 0x00000002,
+       0x55a, 0x00000002,
+       0x55d, 0x000000ff,
+       0x605, 0x00000030,
+       0x608, 0x0000000e,
+       0x609, 0x0000002a,
+       0x652, 0x00000020,
+       0x63c, 0x0000000a,
+       0x63d, 0x0000000e,
+       0x63e, 0x0000000a,
+       0x63f, 0x0000000e,
+       0x66e, 0x00000005,
+       0x700, 0x00000021,
+       0x701, 0x00000043,
+       0x702, 0x00000065,
+       0x703, 0x00000087,
+       0x708, 0x00000021,
+       0x709, 0x00000043,
+       0x70a, 0x00000065,
+       0x70b, 0x00000087,
+};
+
+u32 RTL8723EAGCTAB_1TARRAY[RTL8723E_AGCTAB_1TARRAYLENGTH] = {
+       0xc78, 0x7b000001,
+       0xc78, 0x7b010001,
+       0xc78, 0x7b020001,
+       0xc78, 0x7b030001,
+       0xc78, 0x7b040001,
+       0xc78, 0x7b050001,
+       0xc78, 0x7a060001,
+       0xc78, 0x79070001,
+       0xc78, 0x78080001,
+       0xc78, 0x77090001,
+       0xc78, 0x760a0001,
+       0xc78, 0x750b0001,
+       0xc78, 0x740c0001,
+       0xc78, 0x730d0001,
+       0xc78, 0x720e0001,
+       0xc78, 0x710f0001,
+       0xc78, 0x70100001,
+       0xc78, 0x6f110001,
+       0xc78, 0x6e120001,
+       0xc78, 0x6d130001,
+       0xc78, 0x6c140001,
+       0xc78, 0x6b150001,
+       0xc78, 0x6a160001,
+       0xc78, 0x69170001,
+       0xc78, 0x68180001,
+       0xc78, 0x67190001,
+       0xc78, 0x661a0001,
+       0xc78, 0x651b0001,
+       0xc78, 0x641c0001,
+       0xc78, 0x631d0001,
+       0xc78, 0x621e0001,
+       0xc78, 0x611f0001,
+       0xc78, 0x60200001,
+       0xc78, 0x49210001,
+       0xc78, 0x48220001,
+       0xc78, 0x47230001,
+       0xc78, 0x46240001,
+       0xc78, 0x45250001,
+       0xc78, 0x44260001,
+       0xc78, 0x43270001,
+       0xc78, 0x42280001,
+       0xc78, 0x41290001,
+       0xc78, 0x402a0001,
+       0xc78, 0x262b0001,
+       0xc78, 0x252c0001,
+       0xc78, 0x242d0001,
+       0xc78, 0x232e0001,
+       0xc78, 0x222f0001,
+       0xc78, 0x21300001,
+       0xc78, 0x20310001,
+       0xc78, 0x06320001,
+       0xc78, 0x05330001,
+       0xc78, 0x04340001,
+       0xc78, 0x03350001,
+       0xc78, 0x02360001,
+       0xc78, 0x01370001,
+       0xc78, 0x00380001,
+       0xc78, 0x00390001,
+       0xc78, 0x003a0001,
+       0xc78, 0x003b0001,
+       0xc78, 0x003c0001,
+       0xc78, 0x003d0001,
+       0xc78, 0x003e0001,
+       0xc78, 0x003f0001,
+       0xc78, 0x7b400001,
+       0xc78, 0x7b410001,
+       0xc78, 0x7b420001,
+       0xc78, 0x7b430001,
+       0xc78, 0x7b440001,
+       0xc78, 0x7b450001,
+       0xc78, 0x7a460001,
+       0xc78, 0x79470001,
+       0xc78, 0x78480001,
+       0xc78, 0x77490001,
+       0xc78, 0x764a0001,
+       0xc78, 0x754b0001,
+       0xc78, 0x744c0001,
+       0xc78, 0x734d0001,
+       0xc78, 0x724e0001,
+       0xc78, 0x714f0001,
+       0xc78, 0x70500001,
+       0xc78, 0x6f510001,
+       0xc78, 0x6e520001,
+       0xc78, 0x6d530001,
+       0xc78, 0x6c540001,
+       0xc78, 0x6b550001,
+       0xc78, 0x6a560001,
+       0xc78, 0x69570001,
+       0xc78, 0x68580001,
+       0xc78, 0x67590001,
+       0xc78, 0x665a0001,
+       0xc78, 0x655b0001,
+       0xc78, 0x645c0001,
+       0xc78, 0x635d0001,
+       0xc78, 0x625e0001,
+       0xc78, 0x615f0001,
+       0xc78, 0x60600001,
+       0xc78, 0x49610001,
+       0xc78, 0x48620001,
+       0xc78, 0x47630001,
+       0xc78, 0x46640001,
+       0xc78, 0x45650001,
+       0xc78, 0x44660001,
+       0xc78, 0x43670001,
+       0xc78, 0x42680001,
+       0xc78, 0x41690001,
+       0xc78, 0x406a0001,
+       0xc78, 0x266b0001,
+       0xc78, 0x256c0001,
+       0xc78, 0x246d0001,
+       0xc78, 0x236e0001,
+       0xc78, 0x226f0001,
+       0xc78, 0x21700001,
+       0xc78, 0x20710001,
+       0xc78, 0x06720001,
+       0xc78, 0x05730001,
+       0xc78, 0x04740001,
+       0xc78, 0x03750001,
+       0xc78, 0x02760001,
+       0xc78, 0x01770001,
+       0xc78, 0x00780001,
+       0xc78, 0x00790001,
+       0xc78, 0x007a0001,
+       0xc78, 0x007b0001,
+       0xc78, 0x007c0001,
+       0xc78, 0x007d0001,
+       0xc78, 0x007e0001,
+       0xc78, 0x007f0001,
+       0xc78, 0x3800001e,
+       0xc78, 0x3801001e,
+       0xc78, 0x3802001e,
+       0xc78, 0x3803001e,
+       0xc78, 0x3804001e,
+       0xc78, 0x3805001e,
+       0xc78, 0x3806001e,
+       0xc78, 0x3807001e,
+       0xc78, 0x3808001e,
+       0xc78, 0x3c09001e,
+       0xc78, 0x3e0a001e,
+       0xc78, 0x400b001e,
+       0xc78, 0x440c001e,
+       0xc78, 0x480d001e,
+       0xc78, 0x4c0e001e,
+       0xc78, 0x500f001e,
+       0xc78, 0x5210001e,
+       0xc78, 0x5611001e,
+       0xc78, 0x5a12001e,
+       0xc78, 0x5e13001e,
+       0xc78, 0x6014001e,
+       0xc78, 0x6015001e,
+       0xc78, 0x6016001e,
+       0xc78, 0x6217001e,
+       0xc78, 0x6218001e,
+       0xc78, 0x6219001e,
+       0xc78, 0x621a001e,
+       0xc78, 0x621b001e,
+       0xc78, 0x621c001e,
+       0xc78, 0x621d001e,
+       0xc78, 0x621e001e,
+       0xc78, 0x621f001e,
+};
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/table.h b/drivers/net/wireless/rtlwifi/rtl8723ae/table.h
new file mode 100644 (file)
index 0000000..f5ce713
--- /dev/null
@@ -0,0 +1,50 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Created on  2010/ 5/18,  1:41
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_TABLE__H_
+#define __RTL8723E_TABLE__H_
+
+#include <linux/types.h>
+
+#define RTL8723E_PHY_REG_1TARRAY_LENGTH                372
+extern u32 RTL8723EPHY_REG_1TARRAY[RTL8723E_PHY_REG_1TARRAY_LENGTH];
+#define RTL8723E_PHY_REG_ARRAY_PGLENGTH                336
+extern u32 RTL8723EPHY_REG_ARRAY_PG[RTL8723E_PHY_REG_ARRAY_PGLENGTH];
+#define Rtl8723ERADIOA_1TARRAYLENGTH            282
+extern u32 RTL8723E_RADIOA_1TARRAY[Rtl8723ERADIOA_1TARRAYLENGTH];
+#define RTL8723E_RADIOB_1TARRAYLENGTH          1
+extern u32 RTL8723E_RADIOB_1TARRAY[RTL8723E_RADIOB_1TARRAYLENGTH];
+#define RTL8723E_MACARRAYLENGTH                        172
+extern u32 RTL8723EMAC_ARRAY[RTL8723E_MACARRAYLENGTH];
+#define RTL8723E_AGCTAB_1TARRAYLENGTH          320
+extern u32 RTL8723EAGCTAB_1TARRAY[RTL8723E_AGCTAB_1TARRAYLENGTH];
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.c
new file mode 100644 (file)
index 0000000..87331d8
--- /dev/null
@@ -0,0 +1,670 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#include "../wifi.h"
+#include "../pci.h"
+#include "../base.h"
+#include "../stats.h"
+#include "reg.h"
+#include "def.h"
+#include "phy.h"
+#include "trx.h"
+#include "led.h"
+
+static u8 _rtl8723ae_map_hwqueue_to_fwqueue(struct sk_buff *skb, u8 hw_queue)
+{
+       __le16 fc = rtl_get_fc(skb);
+
+       if (unlikely(ieee80211_is_beacon(fc)))
+               return QSLT_BEACON;
+       if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
+               return QSLT_MGNT;
+
+       return skb->priority;
+}
+
+static void _rtl8723ae_query_rxphystatus(struct ieee80211_hw *hw,
+                       struct rtl_stats *pstatus, u8 *pdesc,
+                       struct rx_fwinfo_8723e *p_drvinfo,
+                       bool bpacket_match_bssid,
+                       bool bpacket_toself, bool packet_beacon)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtlpriv);
+       struct phy_sts_cck_8723e_t *cck_buf;
+       s8 rx_pwr_all, rx_pwr[4];
+       u8 rf_rx_num = 0, evm, pwdb_all;
+       u8 i, max_spatial_stream;
+       u32 rssi, total_rssi = 0;
+       bool is_cck = pstatus->is_cck;
+
+       /* Record it for next packet processing */
+       pstatus->packet_matchbssid = bpacket_match_bssid;
+       pstatus->packet_toself = bpacket_toself;
+       pstatus->packet_beacon = packet_beacon;
+       pstatus->rx_mimo_sig_qual[0] = -1;
+       pstatus->rx_mimo_sig_qual[1] = -1;
+
+       if (is_cck) {
+               u8 report, cck_highpwr;
+
+               /* CCK Driver info Structure is not the same as OFDM packet. */
+               cck_buf = (struct phy_sts_cck_8723e_t *)p_drvinfo;
+
+               /* (1)Hardware does not provide RSSI for CCK
+                * (2)PWDB, Average PWDB cacluated by
+                * hardware (for rate adaptive)
+                */
+               if (ppsc->rfpwr_state == ERFON)
+                       cck_highpwr = (u8) rtl_get_bbreg(hw,
+                                                RFPGA0_XA_HSSIPARAMETER2,
+                                                BIT(9));
+               else
+                       cck_highpwr = false;
+
+               if (!cck_highpwr) {
+                       u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
+                       report = cck_buf->cck_agc_rpt & 0xc0;
+                       report = report >> 6;
+                       switch (report) {
+                       case 0x3:
+                               rx_pwr_all = -46 - (cck_agc_rpt & 0x3e);
+                               break;
+                       case 0x2:
+                               rx_pwr_all = -26 - (cck_agc_rpt & 0x3e);
+                               break;
+                       case 0x1:
+                               rx_pwr_all = -12 - (cck_agc_rpt & 0x3e);
+                               break;
+                       case 0x0:
+                               rx_pwr_all = 16 - (cck_agc_rpt & 0x3e);
+                               break;
+                       }
+               } else {
+                       u8 cck_agc_rpt = cck_buf->cck_agc_rpt;
+                       report = p_drvinfo->cfosho[0] & 0x60;
+                       report = report >> 5;
+                       switch (report) {
+                       case 0x3:
+                               rx_pwr_all = -46 - ((cck_agc_rpt & 0x1f) << 1);
+                               break;
+                       case 0x2:
+                               rx_pwr_all = -26 - ((cck_agc_rpt & 0x1f) << 1);
+                               break;
+                       case 0x1:
+                               rx_pwr_all = -12 - ((cck_agc_rpt & 0x1f) << 1);
+                               break;
+                       case 0x0:
+                               rx_pwr_all = 16 - ((cck_agc_rpt & 0x1f) << 1);
+                               break;
+                       }
+               }
+
+               pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+               /* CCK gain is smaller than OFDM/MCS gain,
+                * so we add gain diff. From experience, the val is 6
+                */
+               pwdb_all += 6;
+               if (pwdb_all > 100)
+                       pwdb_all = 100;
+               /* modify the offset to make the same
+                * gain index with OFDM.
+                */
+               if (pwdb_all > 34 && pwdb_all <= 42)
+                       pwdb_all -= 2;
+               else if (pwdb_all > 26 && pwdb_all <= 34)
+                       pwdb_all -= 6;
+               else if (pwdb_all > 14 && pwdb_all <= 26)
+                       pwdb_all -= 8;
+               else if (pwdb_all > 4 && pwdb_all <= 14)
+                       pwdb_all -= 4;
+
+               pstatus->rx_pwdb_all = pwdb_all;
+               pstatus->recvsignalpower = rx_pwr_all;
+
+               /* (3) Get Signal Quality (EVM) */
+               if (bpacket_match_bssid) {
+                       u8 sq;
+
+                       if (pstatus->rx_pwdb_all > 40) {
+                               sq = 100;
+                       } else {
+                               sq = cck_buf->sq_rpt;
+                               if (sq > 64)
+                                       sq = 0;
+                               else if (sq < 20)
+                                       sq = 100;
+                               else
+                                       sq = ((64 - sq) * 100) / 44;
+                       }
+
+                       pstatus->signalquality = sq;
+                       pstatus->rx_mimo_sig_qual[0] = sq;
+                       pstatus->rx_mimo_sig_qual[1] = -1;
+               }
+       } else {
+               rtlpriv->dm.rfpath_rxenable[0] =
+                   rtlpriv->dm.rfpath_rxenable[1] = true;
+
+               /* (1)Get RSSI for HT rate */
+               for (i = RF90_PATH_A; i < RF6052_MAX_PATH; i++) {
+
+                       /* we will judge RF RX path now. */
+                       if (rtlpriv->dm.rfpath_rxenable[i])
+                               rf_rx_num++;
+
+                       rx_pwr[i] = ((p_drvinfo->gain_trsw[i] & 0x3f)*2) - 110;
+
+                       /* Translate DBM to percentage. */
+                       rssi = rtl_query_rxpwrpercentage(rx_pwr[i]);
+                       total_rssi += rssi;
+
+                       /* Get Rx snr value in DB */
+                       rtlpriv->stats.rx_snr_db[i] = (p_drvinfo->rxsnr[i] / 2);
+
+                       /* Record Signal Strength for next packet */
+                       if (bpacket_match_bssid)
+                               pstatus->rx_mimo_signalstrength[i] = (u8) rssi;
+               }
+
+               /* (2)PWDB, Average PWDB cacluated by
+                * hardware (for rate adaptive)
+                */
+               rx_pwr_all = ((p_drvinfo->pwdb_all >> 1) & 0x7f) - 110;
+
+               pwdb_all = rtl_query_rxpwrpercentage(rx_pwr_all);
+               pstatus->rx_pwdb_all = pwdb_all;
+               pstatus->rxpower = rx_pwr_all;
+               pstatus->recvsignalpower = rx_pwr_all;
+
+               /* (3)EVM of HT rate */
+               if (pstatus->is_ht && pstatus->rate >= DESC92_RATEMCS8 &&
+                   pstatus->rate <= DESC92_RATEMCS15)
+                       max_spatial_stream = 2;
+               else
+                       max_spatial_stream = 1;
+
+               for (i = 0; i < max_spatial_stream; i++) {
+                       evm = rtl_evm_db_to_percentage(p_drvinfo->rxevm[i]);
+
+                       if (bpacket_match_bssid) {
+                               /* Fill value in RFD, Get the first
+                                * spatial stream only
+                                */
+                               if (i == 0)
+                                       pstatus->signalquality = (evm & 0xff);
+                               pstatus->rx_mimo_sig_qual[i] = (evm & 0xff);
+                       }
+               }
+       }
+
+       /* UI BSS List signal strength(in percentage),
+        * make it good looking, from 0~100.
+        */
+       if (is_cck)
+               pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+                       pwdb_all));
+       else if (rf_rx_num != 0)
+               pstatus->signalstrength = (u8)(rtl_signal_scale_mapping(hw,
+                       total_rssi /= rf_rx_num));
+}
+
+static void _rtl8723ae_translate_rx_signal_stuff(struct ieee80211_hw *hw,
+               struct sk_buff *skb, struct rtl_stats *pstatus,
+               u8 *pdesc, struct rx_fwinfo_8723e *p_drvinfo)
+{
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_efuse *rtlefuse = rtl_efuse(rtl_priv(hw));
+       struct ieee80211_hdr *hdr;
+       u8 *tmp_buf;
+       u8 *praddr;
+       u8 *psaddr;
+       __le16 fc;
+       u16 type;
+       bool packet_matchbssid, packet_toself, packet_beacon;
+
+       tmp_buf = skb->data + pstatus->rx_drvinfo_size + pstatus->rx_bufshift;
+
+       hdr = (struct ieee80211_hdr *)tmp_buf;
+       fc = hdr->frame_control;
+       type = WLAN_FC_GET_TYPE(fc);
+       praddr = hdr->addr1;
+       psaddr = ieee80211_get_SA(hdr);
+
+       packet_matchbssid = ((IEEE80211_FTYPE_CTL != type) &&
+                           (!compare_ether_addr(mac->bssid,
+                           (le16_to_cpu(fc) & IEEE80211_FCTL_TODS) ?
+                           hdr->addr1 : (le16_to_cpu(fc) &
+                           IEEE80211_FCTL_FROMDS) ?
+                           hdr->addr2 : hdr->addr3)) && (!pstatus->hwerror) &&
+                           (!pstatus->crc) && (!pstatus->icv));
+
+       packet_toself = packet_matchbssid &&
+           (!compare_ether_addr(praddr, rtlefuse->dev_addr));
+
+       if (ieee80211_is_beacon(fc))
+               packet_beacon = true;
+
+       _rtl8723ae_query_rxphystatus(hw, pstatus, pdesc, p_drvinfo,
+                                  packet_matchbssid, packet_toself,
+                                  packet_beacon);
+
+       rtl_process_phyinfo(hw, tmp_buf, pstatus);
+}
+
+bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
+                            struct rtl_stats *status,
+                            struct ieee80211_rx_status *rx_status,
+                            u8 *pdesc, struct sk_buff *skb)
+{
+       struct rx_fwinfo_8723e *p_drvinfo;
+       struct ieee80211_hdr *hdr;
+       u32 phystatus = GET_RX_DESC_PHYST(pdesc);
+
+       status->length = (u16) GET_RX_DESC_PKT_LEN(pdesc);
+       status->rx_drvinfo_size = (u8) GET_RX_DESC_DRV_INFO_SIZE(pdesc) *
+                                  RX_DRV_INFO_SIZE_UNIT;
+       status->rx_bufshift = (u8) (GET_RX_DESC_SHIFT(pdesc) & 0x03);
+       status->icv = (u16) GET_RX_DESC_ICV(pdesc);
+       status->crc = (u16) GET_RX_DESC_CRC32(pdesc);
+       status->hwerror = (status->crc | status->icv);
+       status->decrypted = !GET_RX_DESC_SWDEC(pdesc);
+       status->rate = (u8) GET_RX_DESC_RXMCS(pdesc);
+       status->shortpreamble = (u16) GET_RX_DESC_SPLCP(pdesc);
+       status->isampdu = (bool) (GET_RX_DESC_PAGGR(pdesc) == 1);
+       status->isfirst_ampdu = (bool) ((GET_RX_DESC_PAGGR(pdesc) == 1)
+                                && (GET_RX_DESC_FAGGR(pdesc) == 1));
+       status->timestamp_low = GET_RX_DESC_TSFL(pdesc);
+       status->rx_is40Mhzpacket = (bool) GET_RX_DESC_BW(pdesc);
+       status->is_ht = (bool)GET_RX_DESC_RXHT(pdesc);
+
+       status->is_cck = RTL8723E_RX_HAL_IS_CCK_RATE(status->rate);
+
+       rx_status->freq = hw->conf.channel->center_freq;
+       rx_status->band = hw->conf.channel->band;
+
+       hdr = (struct ieee80211_hdr *)(skb->data + status->rx_drvinfo_size
+               + status->rx_bufshift);
+
+       if (status->crc)
+               rx_status->flag |= RX_FLAG_FAILED_FCS_CRC;
+
+       if (status->rx_is40Mhzpacket)
+               rx_status->flag |= RX_FLAG_40MHZ;
+
+       if (status->is_ht)
+               rx_status->flag |= RX_FLAG_HT;
+
+       rx_status->flag |= RX_FLAG_MACTIME_START;
+
+       /* hw will set status->decrypted true, if it finds the
+        * frame is open data frame or mgmt frame.
+        * Thus hw will not decrypt a robust managment frame
+        * for IEEE80211w but still set status->decrypted
+        * true, so here we should set it back to undecrypted
+        * for IEEE80211w frame, and mac80211 sw will help
+        * to decrypt it
+        */
+       if (status->decrypted) {
+               if ((ieee80211_is_robust_mgmt_frame(hdr)) &&
+                       (ieee80211_has_protected(hdr->frame_control)))
+                       rx_status->flag &= ~RX_FLAG_DECRYPTED;
+               else
+                       rx_status->flag |= RX_FLAG_DECRYPTED;
+       }
+
+       /* rate_idx: index of data rate into band's
+        * supported rates or MCS index if HT rates
+        * are use (RX_FLAG_HT)
+        */
+       rx_status->rate_idx = rtlwifi_rate_mapping(hw, status->is_ht,
+                                                  status->rate, false);
+
+       rx_status->mactime = status->timestamp_low;
+       if (phystatus == true) {
+               p_drvinfo = (struct rx_fwinfo_8723e *)(skb->data +
+                            status->rx_bufshift);
+
+               _rtl8723ae_translate_rx_signal_stuff(hw,
+                          skb, status, pdesc, p_drvinfo);
+       }
+
+       /*rx_status->qual = status->signal; */
+       rx_status->signal = status->recvsignalpower + 10;
+       /*rx_status->noise = -status->noise; */
+
+       return true;
+}
+
+void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
+                           struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+                           struct ieee80211_tx_info *info,
+                           struct ieee80211_sta *sta,
+                           struct sk_buff *skb, u8 hw_queue,
+                           struct rtl_tcb_desc *ptcdesc)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
+       bool defaultadapter = true;
+       u8 *pdesc = (u8 *) pdesc_tx;
+       u16 seq_number;
+       __le16 fc = hdr->frame_control;
+       u8 fw_qsel = _rtl8723ae_map_hwqueue_to_fwqueue(skb, hw_queue);
+       bool firstseg = ((hdr->seq_ctrl &
+                           cpu_to_le16(IEEE80211_SCTL_FRAG)) == 0);
+       bool lastseg = ((hdr->frame_control &
+                          cpu_to_le16(IEEE80211_FCTL_MOREFRAGS)) == 0);
+       dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+                                           skb->data, skb->len,
+                                           PCI_DMA_TODEVICE);
+       u8 bw_40 = 0;
+
+       if (mac->opmode == NL80211_IFTYPE_STATION) {
+               bw_40 = mac->bw_40;
+       } else if (mac->opmode == NL80211_IFTYPE_AP ||
+               mac->opmode == NL80211_IFTYPE_ADHOC) {
+               if (sta)
+                       bw_40 = sta->ht_cap.cap &
+                               IEEE80211_HT_CAP_SUP_WIDTH_20_40;
+       }
+
+       seq_number = (le16_to_cpu(hdr->seq_ctrl) & IEEE80211_SCTL_SEQ) >> 4;
+
+       rtl_get_tcb_desc(hw, info, sta, skb, ptcdesc);
+
+       CLEAR_PCI_TX_DESC_CONTENT(pdesc, sizeof(struct tx_desc_8723e));
+
+       if (ieee80211_is_nullfunc(fc) || ieee80211_is_ctl(fc)) {
+               firstseg = true;
+               lastseg = true;
+       }
+
+       if (firstseg) {
+               SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+
+               SET_TX_DESC_TX_RATE(pdesc, ptcdesc->hw_rate);
+
+               if (ptcdesc->use_shortgi || ptcdesc->use_shortpreamble)
+                       SET_TX_DESC_DATA_SHORTGI(pdesc, 1);
+
+               if (info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       SET_TX_DESC_AGG_BREAK(pdesc, 1);
+                       SET_TX_DESC_MAX_AGG_NUM(pdesc, 0x14);
+               }
+               SET_TX_DESC_SEQ(pdesc, seq_number);
+
+               SET_TX_DESC_RTS_ENABLE(pdesc, ((ptcdesc->rts_enable &&
+                                               !ptcdesc->
+                                               cts_enable) ? 1 : 0));
+               SET_TX_DESC_HW_RTS_ENABLE(pdesc,
+                                         ((ptcdesc->rts_enable
+                                           || ptcdesc->cts_enable) ? 1 : 0));
+               SET_TX_DESC_CTS2SELF(pdesc, ((ptcdesc->cts_enable) ? 1 : 0));
+               SET_TX_DESC_RTS_STBC(pdesc, ((ptcdesc->rts_stbc) ? 1 : 0));
+
+               SET_TX_DESC_RTS_RATE(pdesc, ptcdesc->rts_rate);
+               SET_TX_DESC_RTS_BW(pdesc, 0);
+               SET_TX_DESC_RTS_SC(pdesc, ptcdesc->rts_sc);
+               SET_TX_DESC_RTS_SHORT(pdesc,
+                                     ((ptcdesc->rts_rate <= DESC92_RATE54M) ?
+                                      (ptcdesc->rts_use_shortpreamble ? 1 : 0)
+                                      : (ptcdesc->rts_use_shortgi ? 1 : 0)));
+
+               if (bw_40) {
+                       if (ptcdesc->packet_bw) {
+                               SET_TX_DESC_DATA_BW(pdesc, 1);
+                               SET_TX_DESC_TX_SUB_CARRIER(pdesc, 3);
+                       } else {
+                               SET_TX_DESC_DATA_BW(pdesc, 0);
+                               SET_TX_DESC_TX_SUB_CARRIER(pdesc,
+                                                        mac->cur_40_prime_sc);
+                       }
+               } else {
+                       SET_TX_DESC_DATA_BW(pdesc, 0);
+                       SET_TX_DESC_TX_SUB_CARRIER(pdesc, 0);
+               }
+
+               SET_TX_DESC_LINIP(pdesc, 0);
+               SET_TX_DESC_PKT_SIZE(pdesc, (u16) skb->len);
+
+               if (sta) {
+                       u8 ampdu_density = sta->ht_cap.ampdu_density;
+                       SET_TX_DESC_AMPDU_DENSITY(pdesc, ampdu_density);
+               }
+
+               if (info->control.hw_key) {
+                       struct ieee80211_key_conf *keyconf =
+                           info->control.hw_key;
+
+                       switch (keyconf->cipher) {
+                       case WLAN_CIPHER_SUITE_WEP40:
+                       case WLAN_CIPHER_SUITE_WEP104:
+                       case WLAN_CIPHER_SUITE_TKIP:
+                               SET_TX_DESC_SEC_TYPE(pdesc, 0x1);
+                               break;
+                       case WLAN_CIPHER_SUITE_CCMP:
+                               SET_TX_DESC_SEC_TYPE(pdesc, 0x3);
+                               break;
+                       default:
+                               SET_TX_DESC_SEC_TYPE(pdesc, 0x0);
+                               break;
+                       }
+               }
+
+               SET_TX_DESC_PKT_ID(pdesc, 0);
+               SET_TX_DESC_QUEUE_SEL(pdesc, fw_qsel);
+
+               SET_TX_DESC_DATA_RATE_FB_LIMIT(pdesc, 0x1F);
+               SET_TX_DESC_RTS_RATE_FB_LIMIT(pdesc, 0xF);
+               SET_TX_DESC_DISABLE_FB(pdesc, 0);
+               SET_TX_DESC_USE_RATE(pdesc, ptcdesc->use_driver_rate ? 1 : 0);
+
+               if (ieee80211_is_data_qos(fc)) {
+                       if (mac->rdg_en) {
+                               RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE,
+                                        "Enable RDG function.\n");
+                               SET_TX_DESC_RDG_ENABLE(pdesc, 1);
+                               SET_TX_DESC_HTC(pdesc, 1);
+                       }
+               }
+       }
+
+       SET_TX_DESC_FIRST_SEG(pdesc, (firstseg ? 1 : 0));
+       SET_TX_DESC_LAST_SEG(pdesc, (lastseg ? 1 : 0));
+
+       SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) skb->len);
+
+       SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+
+       if (rtlpriv->dm.useramask) {
+               SET_TX_DESC_RATE_ID(pdesc, ptcdesc->ratr_index);
+               SET_TX_DESC_MACID(pdesc, ptcdesc->mac_id);
+       } else {
+               SET_TX_DESC_RATE_ID(pdesc, 0xC + ptcdesc->ratr_index);
+               SET_TX_DESC_MACID(pdesc, ptcdesc->ratr_index);
+       }
+
+       if ((!ieee80211_is_data_qos(fc)) && ppsc->fwctrl_lps) {
+               SET_TX_DESC_HWSEQ_EN_8723(pdesc, 1);
+
+               if (!defaultadapter)
+                       SET_TX_DESC_HWSEQ_SEL_8723(pdesc, 1);
+       }
+
+       SET_TX_DESC_MORE_FRAG(pdesc, (lastseg ? 0 : 1));
+
+       if (is_multicast_ether_addr(ieee80211_get_DA(hdr)) ||
+           is_broadcast_ether_addr(ieee80211_get_DA(hdr))) {
+               SET_TX_DESC_BMC(pdesc, 1);
+       }
+
+       RT_TRACE(rtlpriv, COMP_SEND, DBG_TRACE, "\n");
+}
+
+void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw,
+                             u8 *pdesc, bool firstseg,
+                             bool lastseg, struct sk_buff *skb)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
+       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
+       u8 fw_queue = QSLT_BEACON;
+       dma_addr_t mapping = pci_map_single(rtlpci->pdev,
+                                           skb->data, skb->len,
+                                           PCI_DMA_TODEVICE);
+       __le16 fc = hdr->frame_control;
+
+       CLEAR_PCI_TX_DESC_CONTENT(pdesc, TX_DESC_SIZE);
+
+       if (firstseg)
+               SET_TX_DESC_OFFSET(pdesc, USB_HWDESC_HEADER_LEN);
+
+       SET_TX_DESC_TX_RATE(pdesc, DESC92_RATE1M);
+
+       SET_TX_DESC_SEQ(pdesc, 0);
+
+       SET_TX_DESC_LINIP(pdesc, 0);
+
+       SET_TX_DESC_QUEUE_SEL(pdesc, fw_queue);
+
+       SET_TX_DESC_FIRST_SEG(pdesc, 1);
+       SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+       SET_TX_DESC_TX_BUFFER_SIZE(pdesc, (u16) (skb->len));
+
+       SET_TX_DESC_TX_BUFFER_ADDRESS(pdesc, mapping);
+
+       SET_TX_DESC_RATE_ID(pdesc, 7);
+       SET_TX_DESC_MACID(pdesc, 0);
+
+       SET_TX_DESC_OWN(pdesc, 1);
+
+       SET_TX_DESC_PKT_SIZE((u8 *) pdesc, (u16) (skb->len));
+
+       SET_TX_DESC_FIRST_SEG(pdesc, 1);
+       SET_TX_DESC_LAST_SEG(pdesc, 1);
+
+       SET_TX_DESC_OFFSET(pdesc, 0x20);
+
+       SET_TX_DESC_USE_RATE(pdesc, 1);
+
+       if (!ieee80211_is_data_qos(fc)) {
+               SET_TX_DESC_HWSEQ_EN_8723(pdesc, 1);
+               /* SET_TX_DESC_HWSEQ_EN(pdesc, 1); */
+               /* SET_TX_DESC_PKT_ID(pdesc, 8); */
+       }
+
+       RT_PRINT_DATA(rtlpriv, COMP_CMD, DBG_LOUD,
+                     "H2C Tx Cmd Content\n",
+                     pdesc, TX_DESC_SIZE);
+}
+
+void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val)
+{
+       if (istx == true) {
+               switch (desc_name) {
+               case HW_DESC_OWN:
+                       SET_TX_DESC_OWN(pdesc, 1);
+                       break;
+               case HW_DESC_TX_NEXTDESC_ADDR:
+                       SET_TX_DESC_NEXT_DESC_ADDRESS(pdesc, *(u32 *) val);
+                       break;
+               default:
+                       RT_ASSERT(false, "ERR txdesc :%d not process\n",
+                                 desc_name);
+                       break;
+               }
+       } else {
+               switch (desc_name) {
+               case HW_DESC_RXOWN:
+                       SET_RX_DESC_OWN(pdesc, 1);
+                       break;
+               case HW_DESC_RXBUFF_ADDR:
+                       SET_RX_DESC_BUFF_ADDR(pdesc, *(u32 *) val);
+                       break;
+               case HW_DESC_RXPKT_LEN:
+                       SET_RX_DESC_PKT_LEN(pdesc, *(u32 *) val);
+                       break;
+               case HW_DESC_RXERO:
+                       SET_RX_DESC_EOR(pdesc, 1);
+                       break;
+               default:
+                       RT_ASSERT(false, "ERR rxdesc :%d not process\n",
+                                 desc_name);
+                       break;
+               }
+       }
+}
+
+u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name)
+{
+       u32 ret = 0;
+
+       if (istx == true) {
+               switch (desc_name) {
+               case HW_DESC_OWN:
+                       ret = GET_TX_DESC_OWN(pdesc);
+                       break;
+               case HW_DESC_TXBUFF_ADDR:
+                       ret = GET_TX_DESC_TX_BUFFER_ADDRESS(pdesc);
+                       break;
+               default:
+                       RT_ASSERT(false, "ERR txdesc :%d not process\n",
+                                 desc_name);
+                       break;
+               }
+       } else {
+               switch (desc_name) {
+               case HW_DESC_OWN:
+                       ret = GET_RX_DESC_OWN(pdesc);
+                       break;
+               case HW_DESC_RXPKT_LEN:
+                       ret = GET_RX_DESC_PKT_LEN(pdesc);
+                       break;
+               default:
+                       RT_ASSERT(false, "ERR rxdesc :%d not process\n",
+                                 desc_name);
+                       break;
+               }
+       }
+       return ret;
+}
+
+void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       if (hw_queue == BEACON_QUEUE) {
+               rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG, BIT(4));
+       } else {
+               rtl_write_word(rtlpriv, REG_PCIE_CTRL_REG,
+                              BIT(0) << (hw_queue));
+       }
+}
diff --git a/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h b/drivers/net/wireless/rtlwifi/rtl8723ae/trx.h
new file mode 100644 (file)
index 0000000..ad05b54
--- /dev/null
@@ -0,0 +1,725 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL8723E_TRX_H__
+#define __RTL8723E_TRX_H__
+
+#define TX_DESC_SIZE                           64
+#define TX_DESC_AGGR_SUBFRAME_SIZE             32
+
+#define RX_DESC_SIZE                           32
+#define RX_DRV_INFO_SIZE_UNIT                  8
+
+#define        TX_DESC_NEXT_DESC_OFFSET                40
+#define USB_HWDESC_HEADER_LEN                  32
+#define CRCLENGTH                              4
+
+#define SET_TX_DESC_PKT_SIZE(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 0, 16, __val)
+#define SET_TX_DESC_OFFSET(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 16, 8, __val)
+#define SET_TX_DESC_BMC(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 24, 1, __val)
+#define SET_TX_DESC_HTC(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 25, 1, __val)
+#define SET_TX_DESC_LAST_SEG(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 26, 1, __val)
+#define SET_TX_DESC_FIRST_SEG(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 27, 1, __val)
+#define SET_TX_DESC_LINIP(__pdesc, __val)              \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 28, 1, __val)
+#define SET_TX_DESC_NO_ACM(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 29, 1, __val)
+#define SET_TX_DESC_GF(__pdesc, __val)                 \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_TX_DESC_OWN(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_TX_DESC_PKT_SIZE(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc, 0, 16)
+#define GET_TX_DESC_OFFSET(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc, 16, 8)
+#define GET_TX_DESC_BMC(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 24, 1)
+#define GET_TX_DESC_HTC(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 25, 1)
+#define GET_TX_DESC_LAST_SEG(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_TX_DESC_FIRST_SEG(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_TX_DESC_LINIP(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_TX_DESC_NO_ACM(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_TX_DESC_GF(__pdesc)                                \
+       LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_TX_DESC_OWN(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_TX_DESC_MACID(__pdesc, __val)              \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 0, 5, __val)
+#define SET_TX_DESC_AGG_BREAK(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 5, 1, __val)
+#define SET_TX_DESC_BK(__pdesc, __val)                 \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 6, 1, __val)
+#define SET_TX_DESC_RDG_ENABLE(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 7, 1, __val)
+#define SET_TX_DESC_QUEUE_SEL(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 8, 5, __val)
+#define SET_TX_DESC_RDG_NAV_EXT(__pdesc, __val)        \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 13, 1, __val)
+#define SET_TX_DESC_LSIG_TXOP_EN(__pdesc, __val)       \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 14, 1, __val)
+#define SET_TX_DESC_PIFS(__pdesc, __val)               \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 15, 1, __val)
+#define SET_TX_DESC_RATE_ID(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 16, 4, __val)
+#define SET_TX_DESC_NAV_USE_HDR(__pdesc, __val)        \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 20, 1, __val)
+#define SET_TX_DESC_EN_DESC_ID(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 21, 1, __val)
+#define SET_TX_DESC_SEC_TYPE(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 22, 2, __val)
+#define SET_TX_DESC_PKT_OFFSET(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+4, 24, 8, __val)
+
+#define GET_TX_DESC_MACID(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
+#define GET_TX_DESC_AGG_ENABLE(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+4, 5, 1)
+#define GET_TX_DESC_AGG_BREAK(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+4, 6, 1)
+#define GET_TX_DESC_RDG_ENABLE(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+4, 7, 1)
+#define GET_TX_DESC_QUEUE_SEL(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+4, 8, 5)
+#define GET_TX_DESC_RDG_NAV_EXT(__pdesc)               \
+       LE_BITS_TO_4BYTE(__pdesc+4, 13, 1)
+#define GET_TX_DESC_LSIG_TXOP_EN(__pdesc)              \
+       LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_TX_DESC_PIFS(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_TX_DESC_RATE_ID(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_TX_DESC_NAV_USE_HDR(__pdesc)               \
+       LE_BITS_TO_4BYTE(__pdesc+4, 20, 1)
+#define GET_TX_DESC_EN_DESC_ID(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+4, 21, 1)
+#define GET_TX_DESC_SEC_TYPE(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+4, 22, 2)
+#define GET_TX_DESC_PKT_OFFSET(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+4, 24, 8)
+
+#define SET_TX_DESC_RTS_RC(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 0, 6, __val)
+#define SET_TX_DESC_DATA_RC(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 6, 6, __val)
+#define SET_TX_DESC_BAR_RTY_TH(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 14, 2, __val)
+#define SET_TX_DESC_MORE_FRAG(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 17, 1, __val)
+#define SET_TX_DESC_RAW(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 18, 1, __val)
+#define SET_TX_DESC_CCX(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 19, 1, __val)
+#define SET_TX_DESC_AMPDU_DENSITY(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 20, 3, __val)
+#define SET_TX_DESC_ANTSEL_A(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 24, 1, __val)
+#define SET_TX_DESC_ANTSEL_B(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 25, 1, __val)
+#define SET_TX_DESC_TX_ANT_CCK(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 26, 2, __val)
+#define SET_TX_DESC_TX_ANTL(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 28, 2, __val)
+#define SET_TX_DESC_TX_ANT_HT(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+8, 30, 2, __val)
+
+#define GET_TX_DESC_RTS_RC(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc+8, 0, 6)
+#define GET_TX_DESC_DATA_RC(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+8, 6, 6)
+#define GET_TX_DESC_BAR_RTY_TH(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+8, 14, 2)
+#define GET_TX_DESC_MORE_FRAG(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+8, 17, 1)
+#define GET_TX_DESC_RAW(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+8, 18, 1)
+#define GET_TX_DESC_CCX(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+8, 19, 1)
+#define GET_TX_DESC_AMPDU_DENSITY(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc+8, 20, 3)
+#define GET_TX_DESC_ANTSEL_A(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+8, 24, 1)
+#define GET_TX_DESC_ANTSEL_B(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+8, 25, 1)
+#define GET_TX_DESC_TX_ANT_CCK(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+8, 26, 2)
+#define GET_TX_DESC_TX_ANTL(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+8, 28, 2)
+#define GET_TX_DESC_TX_ANT_HT(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+8, 30, 2)
+
+#define SET_TX_DESC_NEXT_HEAP_PAGE(__pdesc, __val)     \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 0, 8, __val)
+#define SET_TX_DESC_TAIL_PAGE(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 8, 8, __val)
+#define SET_TX_DESC_SEQ(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 16, 12, __val)
+#define SET_TX_DESC_PKT_ID(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 28, 4, __val)
+
+#define GET_TX_DESC_NEXT_HEAP_PAGE(__pdesc)            \
+       LE_BITS_TO_4BYTE(__pdesc+12, 0, 8)
+#define GET_TX_DESC_TAIL_PAGE(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+12, 8, 8)
+#define GET_TX_DESC_SEQ(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+12, 16, 12)
+#define GET_TX_DESC_PKT_ID(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc+12, 28, 4)
+
+/* For RTL8723 */
+#define SET_TX_DESC_TRIGGER_INT(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 30, 1, __val)
+#define SET_TX_DESC_HWSEQ_EN_8723(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+12, 31, 1, __val)
+#define SET_TX_DESC_HWSEQ_SEL_8723(__pTxDesc, __Value) \
+       SET_BITS_TO_LE_4BYTE(__pTxDesc+16, 6, 2, __Value)
+
+#define SET_TX_DESC_RTS_RATE(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 0, 5, __val)
+#define SET_TX_DESC_AP_DCFE(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 5, 1, __val)
+#define SET_TX_DESC_QOS(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 6, 1, __val)
+#define SET_TX_DESC_HWSEQ_EN(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 7, 1, __val)
+#define SET_TX_DESC_USE_RATE(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 8, 1, __val)
+#define SET_TX_DESC_DISABLE_RTS_FB(__pdesc, __val)     \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 9, 1, __val)
+#define SET_TX_DESC_DISABLE_FB(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 10, 1, __val)
+#define SET_TX_DESC_CTS2SELF(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 11, 1, __val)
+#define SET_TX_DESC_RTS_ENABLE(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 12, 1, __val)
+#define SET_TX_DESC_HW_RTS_ENABLE(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 13, 1, __val)
+#define SET_TX_DESC_PORT_ID(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 14, 1, __val)
+#define SET_TX_DESC_WAIT_DCTS(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 18, 1, __val)
+#define SET_TX_DESC_CTS2AP_EN(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 19, 1, __val)
+#define SET_TX_DESC_TX_SUB_CARRIER(__pdesc, __val)     \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 20, 2, __val)
+#define SET_TX_DESC_TX_STBC(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 22, 2, __val)
+#define SET_TX_DESC_DATA_SHORT(__pdesc, __val)         \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 24, 1, __val)
+#define SET_TX_DESC_DATA_BW(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 25, 1, __val)
+#define SET_TX_DESC_RTS_SHORT(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 26, 1, __val)
+#define SET_TX_DESC_RTS_BW(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 27, 1, __val)
+#define SET_TX_DESC_RTS_SC(__pdesc, __val)             \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 28, 2, __val)
+#define SET_TX_DESC_RTS_STBC(__pdesc, __val)           \
+       SET_BITS_TO_LE_4BYTE(__pdesc+16, 30, 2, __val)
+
+#define GET_TX_DESC_RTS_RATE(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+16, 0, 5)
+#define GET_TX_DESC_AP_DCFE(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+16, 5, 1)
+#define GET_TX_DESC_QOS(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+16, 6, 1)
+#define GET_TX_DESC_HWSEQ_EN(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+16, 7, 1)
+#define GET_TX_DESC_USE_RATE(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+16, 8, 1)
+#define GET_TX_DESC_DISABLE_RTS_FB(__pdesc)            \
+       LE_BITS_TO_4BYTE(__pdesc+16, 9, 1)
+#define GET_TX_DESC_DISABLE_FB(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+16, 10, 1)
+#define GET_TX_DESC_CTS2SELF(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+16, 11, 1)
+#define GET_TX_DESC_RTS_ENABLE(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+16, 12, 1)
+#define GET_TX_DESC_HW_RTS_ENABLE(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc+16, 13, 1)
+#define GET_TX_DESC_PORT_ID(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+16, 14, 1)
+#define GET_TX_DESC_WAIT_DCTS(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+16, 18, 1)
+#define GET_TX_DESC_CTS2AP_EN(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+16, 19, 1)
+#define GET_TX_DESC_TX_SUB_CARRIER(__pdesc)            \
+       LE_BITS_TO_4BYTE(__pdesc+16, 20, 2)
+#define GET_TX_DESC_TX_STBC(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+16, 22, 2)
+#define GET_TX_DESC_DATA_SHORT(__pdesc)                \
+       LE_BITS_TO_4BYTE(__pdesc+16, 24, 1)
+#define GET_TX_DESC_DATA_BW(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+16, 25, 1)
+#define GET_TX_DESC_RTS_SHORT(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+16, 26, 1)
+#define GET_TX_DESC_RTS_BW(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc+16, 27, 1)
+#define GET_TX_DESC_RTS_SC(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc+16, 28, 2)
+#define GET_TX_DESC_RTS_STBC(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+16, 30, 2)
+
+#define SET_TX_DESC_TX_RATE(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 0, 6, __val)
+#define SET_TX_DESC_DATA_SHORTGI(__pdesc, __val)       \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 6, 1, __val)
+#define SET_TX_DESC_CCX_TAG(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 7, 1, __val)
+#define SET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc, __val) \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 8, 5, __val)
+#define SET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc, __val)  \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 13, 4, __val)
+#define SET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc, __val) \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 17, 1, __val)
+#define SET_TX_DESC_DATA_RETRY_LIMIT(__pdesc, __val)   \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 18, 6, __val)
+#define SET_TX_DESC_USB_TXAGG_NUM(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+20, 24, 8, __val)
+
+#define GET_TX_DESC_TX_RATE(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+20, 0, 6)
+#define GET_TX_DESC_DATA_SHORTGI(__pdesc)              \
+       LE_BITS_TO_4BYTE(__pdesc+20, 6, 1)
+#define GET_TX_DESC_CCX_TAG(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+20, 7, 1)
+#define GET_TX_DESC_DATA_RATE_FB_LIMIT(__pdesc)        \
+       LE_BITS_TO_4BYTE(__pdesc+20, 8, 5)
+#define GET_TX_DESC_RTS_RATE_FB_LIMIT(__pdesc)         \
+       LE_BITS_TO_4BYTE(__pdesc+20, 13, 4)
+#define GET_TX_DESC_RETRY_LIMIT_ENABLE(__pdesc)        \
+       LE_BITS_TO_4BYTE(__pdesc+20, 17, 1)
+#define GET_TX_DESC_DATA_RETRY_LIMIT(__pdesc)          \
+       LE_BITS_TO_4BYTE(__pdesc+20, 18, 6)
+#define GET_TX_DESC_USB_TXAGG_NUM(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+20, 24, 8)
+
+#define SET_TX_DESC_TXAGC_A(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 5, __val)
+#define SET_TX_DESC_TXAGC_B(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 5, 5, __val)
+#define SET_TX_DESC_USE_MAX_LEN(__pdesc, __val)        \
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 10, 1, __val)
+#define SET_TX_DESC_MAX_AGG_NUM(__pdesc, __val)        \
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 11, 5, __val)
+#define SET_TX_DESC_MCSG1_MAX_LEN(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 16, 4, __val)
+#define SET_TX_DESC_MCSG2_MAX_LEN(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 20, 4, __val)
+#define SET_TX_DESC_MCSG3_MAX_LEN(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 24, 4, __val)
+#define SET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc, __val)\
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 28, 4, __val)
+
+#define GET_TX_DESC_TXAGC_A(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+24, 0, 5)
+#define GET_TX_DESC_TXAGC_B(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc+24, 5, 5)
+#define GET_TX_DESC_USE_MAX_LEN(__pdesc)               \
+       LE_BITS_TO_4BYTE(__pdesc+24, 10, 1)
+#define GET_TX_DESC_MAX_AGG_NUM(__pdesc)               \
+       LE_BITS_TO_4BYTE(__pdesc+24, 11, 5)
+#define GET_TX_DESC_MCSG1_MAX_LEN(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc+24, 16, 4)
+#define GET_TX_DESC_MCSG2_MAX_LEN(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc+24, 20, 4)
+#define GET_TX_DESC_MCSG3_MAX_LEN(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc+24, 24, 4)
+#define GET_TX_DESC_MCS7_SGI_MAX_LEN(__pdesc)          \
+       LE_BITS_TO_4BYTE(__pdesc+24, 28, 4)
+
+#define SET_TX_DESC_TX_BUFFER_SIZE(__pdesc, __val)     \
+       SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 16, __val)
+#define SET_TX_DESC_MCSG4_MAX_LEN(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+28, 16, 4, __val)
+#define SET_TX_DESC_MCSG5_MAX_LEN(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+28, 20, 4, __val)
+#define SET_TX_DESC_MCSG6_MAX_LEN(__pdesc, __val)      \
+       SET_BITS_TO_LE_4BYTE(__pdesc+28, 24, 4, __val)
+#define SET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc, __val)  \
+       SET_BITS_TO_LE_4BYTE(__pdesc+28, 28, 4, __val)
+
+#define GET_TX_DESC_TX_BUFFER_SIZE(__pdesc)            \
+       LE_BITS_TO_4BYTE(__pdesc+28, 0, 16)
+#define GET_TX_DESC_MCSG4_MAX_LEN(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc+28, 16, 4)
+#define GET_TX_DESC_MCSG5_MAX_LEN(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc+28, 20, 4)
+#define GET_TX_DESC_MCSG6_MAX_LEN(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc+28, 24, 4)
+#define GET_TX_DESC_MCS15_SGI_MAX_LEN(__pdesc)         \
+       LE_BITS_TO_4BYTE(__pdesc+28, 28, 4)
+
+#define SET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc, __val)  \
+       SET_BITS_TO_LE_4BYTE(__pdesc+32, 0, 32, __val)
+#define SET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc, __val) \
+       SET_BITS_TO_LE_4BYTE(__pdesc+36, 0, 32, __val)
+
+#define GET_TX_DESC_TX_BUFFER_ADDRESS(__pdesc)         \
+       LE_BITS_TO_4BYTE(__pdesc+32, 0, 32)
+#define GET_TX_DESC_TX_BUFFER_ADDRESS64(__pdesc)       \
+       LE_BITS_TO_4BYTE(__pdesc+36, 0, 32)
+
+#define SET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc, __val)  \
+       SET_BITS_TO_LE_4BYTE(__pdesc+40, 0, 32, __val)
+#define SET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc, __val) \
+       SET_BITS_TO_LE_4BYTE(__pdesc+44, 0, 32, __val)
+
+#define GET_TX_DESC_NEXT_DESC_ADDRESS(__pdesc)         \
+       LE_BITS_TO_4BYTE(__pdesc+40, 0, 32)
+#define GET_TX_DESC_NEXT_DESC_ADDRESS64(__pdesc)       \
+       LE_BITS_TO_4BYTE(__pdesc+44, 0, 32)
+
+#define GET_RX_DESC_PKT_LEN(__pdesc)                   \
+       LE_BITS_TO_4BYTE(__pdesc, 0, 14)
+#define GET_RX_DESC_CRC32(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 14, 1)
+#define GET_RX_DESC_ICV(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 15, 1)
+#define GET_RX_DESC_DRV_INFO_SIZE(__pdesc)             \
+       LE_BITS_TO_4BYTE(__pdesc, 16, 4)
+#define GET_RX_DESC_SECURITY(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc, 20, 3)
+#define GET_RX_DESC_QOS(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 23, 1)
+#define GET_RX_DESC_SHIFT(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 24, 2)
+#define GET_RX_DESC_PHYST(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 26, 1)
+#define GET_RX_DESC_SWDEC(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc, 27, 1)
+#define GET_RX_DESC_LS(__pdesc)                                \
+       LE_BITS_TO_4BYTE(__pdesc, 28, 1)
+#define GET_RX_DESC_FS(__pdesc)                                \
+       LE_BITS_TO_4BYTE(__pdesc, 29, 1)
+#define GET_RX_DESC_EOR(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 30, 1)
+#define GET_RX_DESC_OWN(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc, 31, 1)
+
+#define SET_RX_DESC_PKT_LEN(__pdesc, __val)            \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 0, 14, __val)
+#define SET_RX_DESC_EOR(__pdesc, __val)                        \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 30, 1, __val)
+#define SET_RX_DESC_OWN(__pdesc, __val)                        \
+       SET_BITS_TO_LE_4BYTE(__pdesc, 31, 1, __val)
+
+#define GET_RX_DESC_MACID(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+4, 0, 5)
+#define GET_RX_DESC_TID(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+4, 5, 4)
+#define GET_RX_DESC_HWRSVD(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc+4, 9, 5)
+#define GET_RX_DESC_PAGGR(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+4, 14, 1)
+#define GET_RX_DESC_FAGGR(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+4, 15, 1)
+#define GET_RX_DESC_A1_FIT(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc+4, 16, 4)
+#define GET_RX_DESC_A2_FIT(__pdesc)                    \
+       LE_BITS_TO_4BYTE(__pdesc+4, 20, 4)
+#define GET_RX_DESC_PAM(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+4, 24, 1)
+#define GET_RX_DESC_PWR(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+4, 25, 1)
+#define GET_RX_DESC_MD(__pdesc)                                \
+       LE_BITS_TO_4BYTE(__pdesc+4, 26, 1)
+#define GET_RX_DESC_MF(__pdesc)                                \
+       LE_BITS_TO_4BYTE(__pdesc+4, 27, 1)
+#define GET_RX_DESC_TYPE(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+4, 28, 2)
+#define GET_RX_DESC_MC(__pdesc)                                \
+       LE_BITS_TO_4BYTE(__pdesc+4, 30, 1)
+#define GET_RX_DESC_BC(__pdesc)                                \
+       LE_BITS_TO_4BYTE(__pdesc+4, 31, 1)
+#define GET_RX_DESC_SEQ(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+8, 0, 12)
+#define GET_RX_DESC_FRAG(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+8, 12, 4)
+#define GET_RX_DESC_NEXT_PKT_LEN(__pdesc)              \
+       LE_BITS_TO_4BYTE(__pdesc+8, 16, 14)
+#define GET_RX_DESC_NEXT_IND(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+8, 30, 1)
+#define GET_RX_DESC_RSVD(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+8, 31, 1)
+
+#define GET_RX_DESC_RXMCS(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+12, 0, 6)
+#define GET_RX_DESC_RXHT(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+12, 6, 1)
+#define GET_RX_DESC_SPLCP(__pdesc)                     \
+       LE_BITS_TO_4BYTE(__pdesc+12, 8, 1)
+#define GET_RX_DESC_BW(__pdesc)                                \
+       LE_BITS_TO_4BYTE(__pdesc+12, 9, 1)
+#define GET_RX_DESC_HTC(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+12, 10, 1)
+#define GET_RX_DESC_HWPC_ERR(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+12, 14, 1)
+#define GET_RX_DESC_HWPC_IND(__pdesc)                  \
+       LE_BITS_TO_4BYTE(__pdesc+12, 15, 1)
+#define GET_RX_DESC_IV0(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+12, 16, 16)
+
+#define GET_RX_DESC_IV1(__pdesc)                       \
+       LE_BITS_TO_4BYTE(__pdesc+16, 0, 32)
+#define GET_RX_DESC_TSFL(__pdesc)                      \
+       LE_BITS_TO_4BYTE(__pdesc+20, 0, 32)
+
+#define GET_RX_DESC_BUFF_ADDR(__pdesc)                 \
+       LE_BITS_TO_4BYTE(__pdesc+24, 0, 32)
+#define GET_RX_DESC_BUFF_ADDR64(__pdesc)               \
+       LE_BITS_TO_4BYTE(__pdesc+28, 0, 32)
+
+#define SET_RX_DESC_BUFF_ADDR(__pdesc, __val)          \
+       SET_BITS_TO_LE_4BYTE(__pdesc+24, 0, 32, __val)
+#define SET_RX_DESC_BUFF_ADDR64(__pdesc, __val)                \
+       SET_BITS_TO_LE_4BYTE(__pdesc+28, 0, 32, __val)
+
+#define CLEAR_PCI_TX_DESC_CONTENT(__pdesc, _size)      \
+do {                                                   \
+       if (_size > TX_DESC_NEXT_DESC_OFFSET)           \
+               memset(__pdesc, 0, TX_DESC_NEXT_DESC_OFFSET);   \
+       else                                            \
+               memset(__pdesc, 0, _size);              \
+} while (0)
+
+#define RTL8723E_RX_HAL_IS_CCK_RATE(rxmcs)             \
+       ((rxmcs) == DESC92_RATE1M ||                    \
+        (rxmcs) == DESC92_RATE2M ||                    \
+        (rxmcs) == DESC92_RATE5_5M ||                  \
+        (rxmcs) == DESC92_RATE11M)
+
+struct rx_fwinfo_8723e {
+       u8 gain_trsw[4];
+       u8 pwdb_all;
+       u8 cfosho[4];
+       u8 cfotail[4];
+       char rxevm[2];
+       char rxsnr[4];
+       u8 pdsnr[2];
+       u8 csi_current[2];
+       u8 csi_target[2];
+       u8 sigevm;
+       u8 max_ex_pwr;
+       u8 ex_intf_flag:1;
+       u8 sgi_en:1;
+       u8 rxsc:2;
+       u8 reserve:4;
+} __packed;
+
+struct tx_desc_8723e {
+       u32 pktsize:16;
+       u32 offset:8;
+       u32 bmc:1;
+       u32 htc:1;
+       u32 lastseg:1;
+       u32 firstseg:1;
+       u32 linip:1;
+       u32 noacm:1;
+       u32 gf:1;
+       u32 own:1;
+
+       u32 macid:5;
+       u32 agg_en:1;
+       u32 bk:1;
+       u32 rdg_en:1;
+       u32 queuesel:5;
+       u32 rd_nav_ext:1;
+       u32 lsig_txop_en:1;
+       u32 pifs:1;
+       u32 rateid:4;
+       u32 nav_usehdr:1;
+       u32 en_descid:1;
+       u32 sectype:2;
+       u32 pktoffset:8;
+
+       u32 rts_rc:6;
+       u32 data_rc:6;
+       u32 rsvd0:2;
+       u32 bar_retryht:2;
+       u32 rsvd1:1;
+       u32 morefrag:1;
+       u32 raw:1;
+       u32 ccx:1;
+       u32 ampdudensity:3;
+       u32 rsvd2:1;
+       u32 ant_sela:1;
+       u32 ant_selb:1;
+       u32 txant_cck:2;
+       u32 txant_l:2;
+       u32 txant_ht:2;
+
+       u32 nextheadpage:8;
+       u32 tailpage:8;
+       u32 seq:12;
+       u32 pktid:4;
+
+       u32 rtsrate:5;
+       u32 apdcfe:1;
+       u32 qos:1;
+       u32 hwseq_enable:1;
+       u32 userrate:1;
+       u32 dis_rtsfb:1;
+       u32 dis_datafb:1;
+       u32 cts2self:1;
+       u32 rts_en:1;
+       u32 hwrts_en:1;
+       u32 portid:1;
+       u32 rsvd3:3;
+       u32 waitdcts:1;
+       u32 cts2ap_en:1;
+       u32 txsc:2;
+       u32 stbc:2;
+       u32 txshort:1;
+       u32 txbw:1;
+       u32 rtsshort:1;
+       u32 rtsbw:1;
+       u32 rtssc:2;
+       u32 rtsstbc:2;
+
+       u32 txrate:6;
+       u32 shortgi:1;
+       u32 ccxt:1;
+       u32 txrate_fb_lmt:5;
+       u32 rtsrate_fb_lmt:4;
+       u32 retrylmt_en:1;
+       u32 txretrylmt:6;
+       u32 usb_txaggnum:8;
+
+       u32 txagca:5;
+       u32 txagcb:5;
+       u32 usemaxlen:1;
+       u32 maxaggnum:5;
+       u32 mcsg1maxlen:4;
+       u32 mcsg2maxlen:4;
+       u32 mcsg3maxlen:4;
+       u32 mcs7sgimaxlen:4;
+
+       u32 txbuffersize:16;
+       u32 mcsg4maxlen:4;
+       u32 mcsg5maxlen:4;
+       u32 mcsg6maxlen:4;
+       u32 mcsg15sgimaxlen:4;
+
+       u32 txbuffaddr;
+       u32 txbufferaddr64;
+       u32 nextdescaddress;
+       u32 nextdescaddress64;
+
+       u32 reserve_pass_pcie_mm_limit[4];
+} __packed;
+
+struct rx_desc_8723e {
+       u32 length:14;
+       u32 crc32:1;
+       u32 icverror:1;
+       u32 drv_infosize:4;
+       u32 security:3;
+       u32 qos:1;
+       u32 shift:2;
+       u32 phystatus:1;
+       u32 swdec:1;
+       u32 lastseg:1;
+       u32 firstseg:1;
+       u32 eor:1;
+       u32 own:1;
+
+       u32 macid:5;
+       u32 tid:4;
+       u32 hwrsvd:5;
+       u32 paggr:1;
+       u32 faggr:1;
+       u32 a1_fit:4;
+       u32 a2_fit:4;
+       u32 pam:1;
+       u32 pwr:1;
+       u32 moredata:1;
+       u32 morefrag:1;
+       u32 type:2;
+       u32 mc:1;
+       u32 bc:1;
+
+       u32 seq:12;
+       u32 frag:4;
+       u32 nextpktlen:14;
+       u32 nextind:1;
+       u32 rsvd:1;
+
+       u32 rxmcs:6;
+       u32 rxht:1;
+       u32 amsdu:1;
+       u32 splcp:1;
+       u32 bandwidth:1;
+       u32 htc:1;
+       u32 tcpchk_rpt:1;
+       u32 ipcchk_rpt:1;
+       u32 tcpchk_valid:1;
+       u32 hwpcerr:1;
+       u32 hwpcind:1;
+       u32 iv0:16;
+
+       u32 iv1;
+
+       u32 tsfl;
+
+       u32 bufferaddress;
+       u32 bufferaddress64;
+
+} __packed;
+
+void rtl8723ae_tx_fill_desc(struct ieee80211_hw *hw,
+                           struct ieee80211_hdr *hdr, u8 *pdesc_tx,
+                           struct ieee80211_tx_info *info,
+                           struct ieee80211_sta *sta,
+                           struct sk_buff *skb, u8 hw_queue,
+                           struct rtl_tcb_desc *ptcb_desc);
+bool rtl8723ae_rx_query_desc(struct ieee80211_hw *hw,
+                            struct rtl_stats *status,
+                            struct ieee80211_rx_status *rx_status,
+                            u8 *pdesc, struct sk_buff *skb);
+void rtl8723ae_set_desc(u8 *pdesc, bool istx, u8 desc_name, u8 *val);
+u32 rtl8723ae_get_desc(u8 *pdesc, bool istx, u8 desc_name);
+void rtl8723ae_tx_polling(struct ieee80211_hw *hw, u8 hw_queue);
+void rtl8723ae_tx_fill_cmddesc(struct ieee80211_hw *hw, u8 *pdesc,
+                              bool b_firstseg, bool b_lastseg,
+                              struct sk_buff *skb);
+
+#endif
diff --git a/drivers/net/wireless/rtlwifi/stats.c b/drivers/net/wireless/rtlwifi/stats.c
new file mode 100644 (file)
index 0000000..8ed3174
--- /dev/null
@@ -0,0 +1,268 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+#include "wifi.h"
+#include "stats.h"
+#include <linux/export.h>
+
+u8 rtl_query_rxpwrpercentage(char antpower)
+{
+       if ((antpower <= -100) || (antpower >= 20))
+               return 0;
+       else if (antpower >= 0)
+               return 100;
+       else
+               return 100 + antpower;
+}
+EXPORT_SYMBOL(rtl_query_rxpwrpercentage);
+
+u8 rtl_evm_db_to_percentage(char value)
+{
+       char ret_val;
+       ret_val = value;
+
+       if (ret_val >= 0)
+               ret_val = 0;
+       if (ret_val <= -33)
+               ret_val = -33;
+       ret_val = 0 - ret_val;
+       ret_val *= 3;
+       if (ret_val == 99)
+               ret_val = 100;
+
+       return ret_val;
+}
+EXPORT_SYMBOL(rtl_evm_db_to_percentage);
+
+static long rtl_translate_todbm(struct ieee80211_hw *hw,
+                               u8 signal_strength_index)
+{
+       long signal_power;
+
+       signal_power = (long)((signal_strength_index + 1) >> 1);
+       signal_power -= 95;
+       return signal_power;
+}
+
+long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig)
+{
+       long retsig;
+
+       if (currsig >= 61 && currsig <= 100)
+               retsig = 90 + ((currsig - 60) / 4);
+       else if (currsig >= 41 && currsig <= 60)
+               retsig = 78 + ((currsig - 40) / 2);
+       else if (currsig >= 31 && currsig <= 40)
+               retsig = 66 + (currsig - 30);
+       else if (currsig >= 21 && currsig <= 30)
+               retsig = 54 + (currsig - 20);
+       else if (currsig >= 5 && currsig <= 20)
+               retsig = 42 + (((currsig - 5) * 2) / 3);
+       else if (currsig == 4)
+               retsig = 36;
+       else if (currsig == 3)
+               retsig = 27;
+       else if (currsig == 2)
+               retsig = 18;
+       else if (currsig == 1)
+               retsig = 9;
+       else
+               retsig = currsig;
+
+       return retsig;
+}
+EXPORT_SYMBOL(rtl_signal_scale_mapping);
+
+static void rtl_process_ui_rssi(struct ieee80211_hw *hw,
+                               struct rtl_stats *pstatus)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_phy *rtlphy = &(rtlpriv->phy);
+       u8 rfpath;
+       u32 last_rssi, tmpval;
+
+       rtlpriv->stats.rssi_calculate_cnt++;
+
+       if (rtlpriv->stats.ui_rssi.total_num++ >= PHY_RSSI_SLID_WIN_MAX) {
+               rtlpriv->stats.ui_rssi.total_num = PHY_RSSI_SLID_WIN_MAX;
+               last_rssi = rtlpriv->stats.ui_rssi.elements[
+                       rtlpriv->stats.ui_rssi.index];
+               rtlpriv->stats.ui_rssi.total_val -= last_rssi;
+       }
+       rtlpriv->stats.ui_rssi.total_val += pstatus->signalstrength;
+       rtlpriv->stats.ui_rssi.elements[rtlpriv->stats.ui_rssi.index++] =
+           pstatus->signalstrength;
+       if (rtlpriv->stats.ui_rssi.index >= PHY_RSSI_SLID_WIN_MAX)
+               rtlpriv->stats.ui_rssi.index = 0;
+       tmpval = rtlpriv->stats.ui_rssi.total_val /
+               rtlpriv->stats.ui_rssi.total_num;
+       rtlpriv->stats.signal_strength = rtl_translate_todbm(hw,
+               (u8) tmpval);
+       pstatus->rssi = rtlpriv->stats.signal_strength;
+
+       if (pstatus->is_cck)
+               return;
+
+       for (rfpath = RF90_PATH_A; rfpath < rtlphy->num_total_rfpath;
+            rfpath++) {
+               if (rtlpriv->stats.rx_rssi_percentage[rfpath] == 0) {
+                       rtlpriv->stats.rx_rssi_percentage[rfpath] =
+                           pstatus->rx_mimo_signalstrength[rfpath];
+
+               }
+               if (pstatus->rx_mimo_signalstrength[rfpath] >
+                   rtlpriv->stats.rx_rssi_percentage[rfpath]) {
+                       rtlpriv->stats.rx_rssi_percentage[rfpath] =
+                           ((rtlpriv->stats.rx_rssi_percentage[rfpath] *
+                             (RX_SMOOTH_FACTOR - 1)) +
+                            (pstatus->rx_mimo_signalstrength[rfpath])) /
+                           (RX_SMOOTH_FACTOR);
+                       rtlpriv->stats.rx_rssi_percentage[rfpath] =
+                           rtlpriv->stats.rx_rssi_percentage[rfpath] + 1;
+               } else {
+                       rtlpriv->stats.rx_rssi_percentage[rfpath] =
+                           ((rtlpriv->stats.rx_rssi_percentage[rfpath] *
+                             (RX_SMOOTH_FACTOR - 1)) +
+                            (pstatus->rx_mimo_signalstrength[rfpath])) /
+                           (RX_SMOOTH_FACTOR);
+               }
+       }
+}
+
+static void rtl_update_rxsignalstatistics(struct ieee80211_hw *hw,
+                                         struct rtl_stats *pstatus)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       int weighting = 0;
+
+       if (rtlpriv->stats.recv_signal_power == 0)
+               rtlpriv->stats.recv_signal_power = pstatus->recvsignalpower;
+       if (pstatus->recvsignalpower > rtlpriv->stats.recv_signal_power)
+               weighting = 5;
+       else if (pstatus->recvsignalpower < rtlpriv->stats.recv_signal_power)
+               weighting = (-5);
+       rtlpriv->stats.recv_signal_power = (rtlpriv->stats.recv_signal_power *
+               5 + pstatus->recvsignalpower + weighting) / 6;
+}
+
+static void rtl_process_pwdb(struct ieee80211_hw *hw, struct rtl_stats *pstatus)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_sta_info *drv_priv = NULL;
+       struct ieee80211_sta *sta = NULL;
+       long undec_sm_pwdb;
+
+       rcu_read_lock();
+       if (rtlpriv->mac80211.opmode != NL80211_IFTYPE_STATION)
+               sta = rtl_find_sta(hw, pstatus->psaddr);
+
+       /* adhoc or ap mode */
+       if (sta) {
+               drv_priv = (struct rtl_sta_info *) sta->drv_priv;
+               undec_sm_pwdb = drv_priv->rssi_stat.undec_sm_pwdb;
+       } else {
+               undec_sm_pwdb = rtlpriv->dm.undec_sm_pwdb;
+       }
+
+       if (undec_sm_pwdb < 0)
+               undec_sm_pwdb = pstatus->rx_pwdb_all;
+       if (pstatus->rx_pwdb_all > (u32) undec_sm_pwdb) {
+               undec_sm_pwdb = (((undec_sm_pwdb) *
+                     (RX_SMOOTH_FACTOR - 1)) +
+                    (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+               undec_sm_pwdb = undec_sm_pwdb + 1;
+       } else {
+               undec_sm_pwdb = (((undec_sm_pwdb) * (RX_SMOOTH_FACTOR - 1)) +
+                    (pstatus->rx_pwdb_all)) / (RX_SMOOTH_FACTOR);
+       }
+
+       if (sta) {
+               drv_priv->rssi_stat.undec_sm_pwdb = undec_sm_pwdb;
+       } else {
+               rtlpriv->dm.undec_sm_pwdb = undec_sm_pwdb;
+       }
+       rcu_read_unlock();
+
+       rtl_update_rxsignalstatistics(hw, pstatus);
+}
+
+static void rtl_process_ui_link_quality(struct ieee80211_hw *hw,
+                                       struct rtl_stats *pstatus)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       u32 last_evm, n_stream, tmpval;
+
+       if (pstatus->signalquality == 0)
+               return;
+
+       if (rtlpriv->stats.ui_link_quality.total_num++ >=
+           PHY_LINKQUALITY_SLID_WIN_MAX) {
+               rtlpriv->stats.ui_link_quality.total_num =
+                   PHY_LINKQUALITY_SLID_WIN_MAX;
+               last_evm = rtlpriv->stats.ui_link_quality.elements[
+                       rtlpriv->stats.ui_link_quality.index];
+               rtlpriv->stats.ui_link_quality.total_val -= last_evm;
+       }
+       rtlpriv->stats.ui_link_quality.total_val += pstatus->signalquality;
+       rtlpriv->stats.ui_link_quality.elements[
+               rtlpriv->stats.ui_link_quality.index++] =
+                                                pstatus->signalquality;
+       if (rtlpriv->stats.ui_link_quality.index >=
+           PHY_LINKQUALITY_SLID_WIN_MAX)
+               rtlpriv->stats.ui_link_quality.index = 0;
+       tmpval = rtlpriv->stats.ui_link_quality.total_val /
+           rtlpriv->stats.ui_link_quality.total_num;
+       rtlpriv->stats.signal_quality = tmpval;
+       rtlpriv->stats.last_sigstrength_inpercent = tmpval;
+       for (n_stream = 0; n_stream < 2; n_stream++) {
+               if (pstatus->rx_mimo_sig_qual[n_stream] != -1) {
+                       if (rtlpriv->stats.rx_evm_percentage[n_stream] == 0) {
+                               rtlpriv->stats.rx_evm_percentage[n_stream] =
+                                   pstatus->rx_mimo_sig_qual[n_stream];
+                       }
+                       rtlpriv->stats.rx_evm_percentage[n_stream] =
+                           ((rtlpriv->stats.rx_evm_percentage[n_stream]
+                             * (RX_SMOOTH_FACTOR - 1)) +
+                            (pstatus->rx_mimo_sig_qual[n_stream] * 1)) /
+                           (RX_SMOOTH_FACTOR);
+               }
+       }
+}
+
+void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer,
+       struct rtl_stats *pstatus)
+{
+
+       if (!pstatus->packet_matchbssid)
+               return;
+
+       rtl_process_ui_rssi(hw, pstatus);
+       rtl_process_pwdb(hw, pstatus);
+       rtl_process_ui_link_quality(hw, pstatus);
+}
+EXPORT_SYMBOL(rtl_process_phyinfo);
diff --git a/drivers/net/wireless/rtlwifi/stats.h b/drivers/net/wireless/rtlwifi/stats.h
new file mode 100644 (file)
index 0000000..0dbdc52
--- /dev/null
@@ -0,0 +1,46 @@
+/******************************************************************************
+ *
+ * Copyright(c) 2009-2012  Realtek Corporation.
+ *
+ * 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
+ * published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful, but WITHOUT
+ * ANY WARRANTY; without even the implied warranty of MERCHANTABILITY or
+ * FITNESS FOR A PARTICULAR PURPOSE.  See the GNU General Public License for
+ * more details.
+ *
+ * You should have received a copy of the GNU General Public License along with
+ * this program; if not, write to the Free Software Foundation, Inc.,
+ * 51 Franklin Street, Fifth Floor, Boston, MA 02110, USA
+ *
+ * The full GNU General Public License is included in this distribution in the
+ * file called LICENSE.
+ *
+ * Contact Information:
+ * wlanfae <wlanfae@realtek.com>
+ * Realtek Corporation, No. 2, Innovation Road II, Hsinchu Science Park,
+ * Hsinchu 300, Taiwan.
+ *
+ * Larry Finger <Larry.Finger@lwfinger.net>
+ *
+ *****************************************************************************/
+
+#ifndef __RTL_STATS_H__
+#define __RTL_STATS_H__
+
+#define        PHY_RSSI_SLID_WIN_MAX                   100
+#define        PHY_LINKQUALITY_SLID_WIN_MAX            20
+#define        PHY_BEACON_RSSI_SLID_WIN_MAX            10
+
+/* Rx smooth factor */
+#define        RX_SMOOTH_FACTOR                        20
+
+u8 rtl_query_rxpwrpercentage(char antpower);
+u8 rtl_evm_db_to_percentage(char value);
+long rtl_signal_scale_mapping(struct ieee80211_hw *hw, long currsig);
+void rtl_process_phyinfo(struct ieee80211_hw *hw, u8 *buffer,
+       struct rtl_stats *pstatus);
+
+#endif
index 6794b688dd7d90addf9f76f997e38fc742d5505a..21a5f4f4a13509da671834fe196d0fca19fa2b9f 100644 (file)
@@ -350,6 +350,11 @@ enum rt_oem_id {
        RT_CID_819x_WNC_COREGA = 31,
        RT_CID_819x_Foxcoon = 32,
        RT_CID_819x_DELL = 33,
+       RT_CID_819x_PRONETS = 34,
+       RT_CID_819x_Edimax_ASUS = 35,
+       RT_CID_NETGEAR = 36,
+       RT_CID_PLANEX = 37,
+       RT_CID_CC_C = 38,
 };
 
 enum hw_descs {
@@ -505,6 +510,7 @@ enum rtl_var_map {
        RTL_IMR_ROK,            /*Receive DMA OK Interrupt */
        RTL_IBSS_INT_MASKS,     /*(RTL_IMR_BcnInt | RTL_IMR_TBDOK |
                                 * RTL_IMR_TBDER) */
+       RTL_IMR_C2HCMD,         /*fw interrupt*/
 
        /*CCK Rates, TxHT = 0 */
        RTL_RC_CCK_RATE1M,
@@ -661,6 +667,11 @@ enum ba_action {
        ACT_DELBA = 2,
 };
 
+enum rt_polarity_ctl {
+       RT_POLARITY_LOW_ACT = 0,
+       RT_POLARITY_HIGH_ACT = 1,
+};
+
 struct octet_string {
        u8 *octet;
        u16 length;
@@ -903,6 +914,8 @@ struct rtl_phy {
        u8 num_total_rfpath;
        struct phy_parameters hwparam_tables[MAX_TAB];
        u16 rf_pathmap;
+
+       enum rt_polarity_ctl polarity_ctl;
 };
 
 #define MAX_TID_COUNT                          9
@@ -1042,13 +1055,64 @@ struct rtl_mac {
        /*QOS & EDCA */
        struct ieee80211_tx_queue_params edca_param[RTL_MAC80211_NUM_QUEUE];
        struct rtl_qos_parameters ac[AC_MAX];
+
+       /* counters */
+       u64 last_txok_cnt;
+       u64 last_rxok_cnt;
+       u32 last_bt_edca_ul;
+       u32 last_bt_edca_dl;
+};
+
+struct btdm_8723 {
+       bool all_off;
+       bool agc_table_en;
+       bool adc_back_off_on;
+       bool b2_ant_hid_en;
+       bool low_penalty_rate_adaptive;
+       bool rf_rx_lpf_shrink;
+       bool reject_aggre_pkt;
+       bool tra_tdma_on;
+       u8 tra_tdma_nav;
+       u8 tra_tdma_ant;
+       bool tdma_on;
+       u8 tdma_ant;
+       u8 tdma_nav;
+       u8 tdma_dac_swing;
+       u8 fw_dac_swing_lvl;
+       bool ps_tdma_on;
+       u8 ps_tdma_byte[5];
+       bool pta_on;
+       u32 val_0x6c0;
+       u32 val_0x6c8;
+       u32 val_0x6cc;
+       bool sw_dac_swing_on;
+       u32 sw_dac_swing_lvl;
+       u32 wlan_act_hi;
+       u32 wlan_act_lo;
+       u32 bt_retry_index;
+       bool dec_bt_pwr;
+       bool ignore_wlan_act;
+};
+
+struct bt_coexist_8723 {
+       u32 high_priority_tx;
+       u32 high_priority_rx;
+       u32 low_priority_tx;
+       u32 low_priority_rx;
+       u8 c2h_bt_info;
+       bool c2h_bt_info_req_sent;
+       bool c2h_bt_inquiry_page;
+       u32 bt_inq_page_start_time;
+       u8 bt_retry_cnt;
+       u8 c2h_bt_info_original;
+       u8 bt_inquiry_page_cnt;
+       struct btdm_8723 btdm;
 };
 
 struct rtl_hal {
        struct ieee80211_hw *hw;
-
+       struct bt_coexist_8723 hal_coex_8723;
        bool up_first_time;
-       bool first_init;
        bool being_init_adapter;
        bool bbrf_ready;
 
@@ -1312,6 +1376,7 @@ struct rtl_ps_ctl {
 };
 
 struct rtl_stats {
+       u8 psaddr[ETH_ALEN];
        u32 mac_time[2];
        s8 rssi;
        u8 signal;
@@ -1503,6 +1568,7 @@ struct rtl_hal_ops {
        void (*phy_lc_calibrate) (struct ieee80211_hw *hw, bool is2t);
        void (*phy_set_bw_mode_callback) (struct ieee80211_hw *hw);
        void (*dm_dynamic_txpower) (struct ieee80211_hw *hw);
+       void (*c2h_command_handle) (struct ieee80211_hw *hw);
        void (*bt_wifi_media_status_notify) (struct ieee80211_hw *hw,
                                             bool mstate);
        void (*bt_coex_off_before_lps) (struct ieee80211_hw *hw);
@@ -1784,9 +1850,22 @@ struct rtl_priv {
        struct dig_t dm_digtable;
        struct ps_t dm_pstable;
 
-       /* data buffer pointer for USB reads */
-       __le32 *usb_data;
-       int usb_data_index;
+       /* section shared by individual drivers */
+       union {
+               struct {        /* data buffer pointer for USB reads */
+                       __le32 *usb_data;
+                       int usb_data_index;
+                       bool initialized;
+               };
+               struct {        /* section for 8723ae */
+                       bool reg_init;  /* true if regs saved */
+                       u32 reg_874;
+                       u32 reg_c70;
+                       u32 reg_85c;
+                       u32 reg_a74;
+                       bool bt_operation_on;
+               };
+       };
 
        /*This must be the last item so
           that it points to the data allocated
@@ -1818,6 +1897,7 @@ enum bt_co_type {
        BT_CSR_BC4 = 3,
        BT_CSR_BC8 = 4,
        BT_RTL8756 = 5,
+       BT_RTL8723A = 6,
 };
 
 enum bt_cur_state {
@@ -1876,13 +1956,27 @@ struct bt_coexist_info {
 
        bool fw_coexist_all_off;
        bool sw_coexist_all_off;
-       u32 current_state;
+       bool hw_coexist_all_off;
+       u32 cstate;
        u32 previous_state;
+       u32 cstate_h;
+       u32 previous_state_h;
+
        u8 bt_pre_rssi_state;
+       u8 bt_pre_rssi_state1;
 
        u8 reg_bt_iso;
        u8 reg_bt_sco;
-
+       bool balance_on;
+       u8 bt_active_zero_cnt;
+       bool cur_bt_disabled;
+       bool pre_bt_disabled;
+
+       u8 bt_profile_case;
+       u8 bt_profile_action;
+       bool bt_busy;
+       bool hold_for_bt_operation;
+       u8 lps_counter;
 };
 
 
index 6af35265c900173cc58dcf36c0c68a5b595e3157..23289d49dd31806210566fe2aa737154eecf482e 100644 (file)
@@ -81,7 +81,7 @@ static void wl1251_rx_status(struct wl1251 *wl,
        status->freq = ieee80211_channel_to_frequency(desc->channel,
                                                      status->band);
 
-       status->flag |= RX_FLAG_MACTIME_MPDU;
+       status->flag |= RX_FLAG_MACTIME_START;
 
        if (desc->flags & RX_DESC_ENCRYPTION_MASK) {
                status->flag |= RX_FLAG_IV_STRIPPED | RX_FLAG_MMIC_STRIPPED;
index 25530c8760cb0a07234f753efe66e31fbf107c2d..4f1a05b92d2d9022ac82bd97cd3e0b0da53f2724 100644 (file)
@@ -677,7 +677,7 @@ static void wl12xx_get_vif_count(struct ieee80211_hw *hw,
        memset(data, 0, sizeof(*data));
        data->cur_vif = cur_vif;
 
-       ieee80211_iterate_active_interfaces(hw,
+       ieee80211_iterate_active_interfaces(hw, IEEE80211_IFACE_ITER_RESUME_ALL,
                                            wl12xx_vif_count_iter, data);
 }
 
@@ -3791,7 +3791,7 @@ static void wl1271_bss_info_changed_ap(struct wl1271 *wl,
 
        /* Handle HT information change */
        if ((changed & BSS_CHANGED_HT) &&
-           (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+           (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
                ret = wl1271_acx_set_ht_information(wl, wlvif,
                                        bss_conf->ht_operation_mode);
                if (ret < 0) {
@@ -3905,7 +3905,8 @@ sta_not_found:
                        u32 rates;
                        int ieoffset;
                        wlvif->aid = bss_conf->aid;
-                       wlvif->channel_type = bss_conf->channel_type;
+                       wlvif->channel_type =
+                               cfg80211_get_chandef_type(&bss_conf->chandef);
                        wlvif->beacon_int = bss_conf->beacon_int;
                        do_join = true;
                        set_assoc = true;
@@ -4071,7 +4072,7 @@ sta_not_found:
        /* Handle new association with HT. Do this after join. */
        if (sta_exists) {
                if ((changed & BSS_CHANGED_HT) &&
-                   (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+                   (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
                        ret = wl1271_acx_set_ht_capabilities(wl,
                                                             &sta_ht_cap,
                                                             true,
@@ -4098,7 +4099,7 @@ sta_not_found:
 
        /* Handle HT information change. Done after join. */
        if ((changed & BSS_CHANGED_HT) &&
-           (bss_conf->channel_type != NL80211_CHAN_NO_HT)) {
+           (bss_conf->chandef.width != NL80211_CHAN_WIDTH_20_NOHT)) {
                ret = wl1271_acx_set_ht_information(wl, wlvif,
                                        bss_conf->ht_operation_mode);
                if (ret < 0) {
index fb430d8823523b7a8b784dd8a04c6a4774d1fd5f..7da9071b68b60669c7d24441dee721b1c82c87fd 100644 (file)
@@ -26,7 +26,7 @@
 #include <linux/interrupt.h>
 #include <linux/delay.h>
 
-#include <linux/nfc/pn544.h>
+#include <linux/platform_data/pn544.h>
 
 #include <net/nfc/hci.h>
 #include <net/nfc/llc.h>
index fd15d98297056f26381d8f7131e1ead8e0d0f868..93b1e091b1e92460cf473308c8a7ea953b2d493f 100644 (file)
@@ -157,6 +157,7 @@ struct bcma_host_ops {
 
 /* Chip IDs of SoCs */
 #define BCMA_CHIP_ID_BCM4706   0x5300
+#define  BCMA_PKG_ID_BCM4706L  1
 #define BCMA_CHIP_ID_BCM4716   0x4716
 #define  BCMA_PKG_ID_BCM4716   8
 #define  BCMA_PKG_ID_BCM4717   9
@@ -166,7 +167,11 @@ struct bcma_host_ops {
 #define BCMA_CHIP_ID_BCM4749   0x4749
 #define BCMA_CHIP_ID_BCM5356   0x5356
 #define BCMA_CHIP_ID_BCM5357   0x5357
+#define  BCMA_PKG_ID_BCM5358   9
+#define  BCMA_PKG_ID_BCM47186  10
+#define  BCMA_PKG_ID_BCM5357   11
 #define BCMA_CHIP_ID_BCM53572  53572
+#define  BCMA_PKG_ID_BCM47188  9
 
 struct bcma_device {
        struct bcma_bus *bus;
index 85764a9007313186f3695ced71f31ba9893ff6be..f9c5a787d35060f54b459246e099a820ece8b38e 100644 (file)
 
 #define IEEE80211_MAX_MESH_ID_LEN      32
 
+#define IEEE80211_NUM_TIDS             16
+
 #define IEEE80211_QOS_CTL_LEN          2
 /* 1d tag mask */
 #define IEEE80211_QOS_CTL_TAG1D_MASK           0x0007
@@ -665,6 +667,21 @@ struct ieee80211_meshconf_ie {
        u8 meshconf_cap;
 } __attribute__ ((packed));
 
+/**
+ * enum mesh_config_capab_flags - Mesh Configuration IE capability field flags
+ *
+ * @IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish
+ *     additional mesh peerings with other mesh STAs
+ * @IEEE80211_MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs
+ * @IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure
+ *     is ongoing
+ */
+enum mesh_config_capab_flags {
+       IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS          = 0x01,
+       IEEE80211_MESHCONF_CAPAB_FORWARDING             = 0x08,
+       IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING         = 0x20,
+};
+
 /**
  * struct ieee80211_rann_ie
  *
@@ -905,6 +922,38 @@ struct ieee80211_tdls_data {
        } u;
 } __packed;
 
+/*
+ * Peer-to-Peer IE attribute related definitions.
+ */
+/**
+ * enum ieee80211_p2p_attr_id - identifies type of peer-to-peer attribute.
+ */
+enum ieee80211_p2p_attr_id {
+       IEEE80211_P2P_ATTR_STATUS = 0,
+       IEEE80211_P2P_ATTR_MINOR_REASON,
+       IEEE80211_P2P_ATTR_CAPABILITY,
+       IEEE80211_P2P_ATTR_DEVICE_ID,
+       IEEE80211_P2P_ATTR_GO_INTENT,
+       IEEE80211_P2P_ATTR_GO_CONFIG_TIMEOUT,
+       IEEE80211_P2P_ATTR_LISTEN_CHANNEL,
+       IEEE80211_P2P_ATTR_GROUP_BSSID,
+       IEEE80211_P2P_ATTR_EXT_LISTEN_TIMING,
+       IEEE80211_P2P_ATTR_INTENDED_IFACE_ADDR,
+       IEEE80211_P2P_ATTR_MANAGABILITY,
+       IEEE80211_P2P_ATTR_CHANNEL_LIST,
+       IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
+       IEEE80211_P2P_ATTR_DEVICE_INFO,
+       IEEE80211_P2P_ATTR_GROUP_INFO,
+       IEEE80211_P2P_ATTR_GROUP_ID,
+       IEEE80211_P2P_ATTR_INTERFACE,
+       IEEE80211_P2P_ATTR_OPER_CHANNEL,
+       IEEE80211_P2P_ATTR_INVITE_FLAGS,
+       /* 19 - 220: Reserved */
+       IEEE80211_P2P_ATTR_VENDOR_SPECIFIC = 221,
+
+       IEEE80211_P2P_ATTR_MAX
+};
+
 /**
  * struct ieee80211_bar - HT Block Ack Request
  *
@@ -1114,11 +1163,13 @@ struct ieee80211_ht_operation {
  *     STA can receive. Rate expressed in units of 1 Mbps.
  *     If this field is 0 this value should not be used to
  *     consider the highest RX data rate supported.
+ *     The top 3 bits of this field are reserved.
  * @tx_mcs_map: TX MCS map 2 bits for each stream, total 8 streams
  * @tx_highest: Indicates highest long GI VHT PPDU data rate
  *     STA can transmit. Rate expressed in units of 1 Mbps.
  *     If this field is 0 this value should not be used to
  *     consider the highest TX data rate supported.
+ *     The top 3 bits of this field are reserved.
  */
 struct ieee80211_vht_mcs_info {
        __le16 rx_mcs_map;
@@ -1127,6 +1178,27 @@ struct ieee80211_vht_mcs_info {
        __le16 tx_highest;
 } __packed;
 
+/**
+ * enum ieee80211_vht_mcs_support - VHT MCS support definitions
+ * @IEEE80211_VHT_MCS_SUPPORT_0_7: MCSes 0-7 are supported for the
+ *     number of streams
+ * @IEEE80211_VHT_MCS_SUPPORT_0_8: MCSes 0-8 are supported
+ * @IEEE80211_VHT_MCS_SUPPORT_0_9: MCSes 0-9 are supported
+ * @IEEE80211_VHT_MCS_NOT_SUPPORTED: This number of streams isn't supported
+ *
+ * These definitions are used in each 2-bit subfield of the @rx_mcs_map
+ * and @tx_mcs_map fields of &struct ieee80211_vht_mcs_info, which are
+ * both split into 8 subfields by number of streams. These values indicate
+ * which MCSes are supported for the number of streams the value appears
+ * for.
+ */
+enum ieee80211_vht_mcs_support {
+       IEEE80211_VHT_MCS_SUPPORT_0_7   = 0,
+       IEEE80211_VHT_MCS_SUPPORT_0_8   = 1,
+       IEEE80211_VHT_MCS_SUPPORT_0_9   = 2,
+       IEEE80211_VHT_MCS_NOT_SUPPORTED = 3,
+};
+
 /**
  * struct ieee80211_vht_cap - VHT capabilities
  *
diff --git a/include/linux/nfc/pn544.h b/include/linux/nfc/pn544.h
deleted file mode 100644 (file)
index 9890bba..0000000
+++ /dev/null
@@ -1,104 +0,0 @@
-/*
- * Driver include for the PN544 NFC chip.
- *
- * Copyright (C) Nokia Corporation
- *
- * Author: Jari Vanhala <ext-jari.vanhala@nokia.com>
- * Contact: Matti Aaltoenn <matti.j.aaltonen@nokia.com>
- *
- * This program is free software; you can redistribute it and/or
- * modify it under the terms of the GNU General Public License
- * version 2 as published by the Free Software Foundation.
- *
- * This program is distributed in the hope that it will be useful,
- * but WITHOUT ANY WARRANTY; without even the implied warranty of
- * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the
- * GNU General Public License for more details.
- *
- * You should have received a copy of the GNU General Public License
- * along with this program; if not, write to the Free Software
- * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
- */
-
-#ifndef _PN544_H_
-#define _PN544_H_
-
-#include <linux/i2c.h>
-
-#define PN544_DRIVER_NAME      "pn544"
-#define PN544_MAXWINDOW_SIZE   7
-#define PN544_WINDOW_SIZE      4
-#define PN544_RETRIES          10
-#define PN544_MAX_I2C_TRANSFER 0x0400
-#define PN544_MSG_MAX_SIZE     0x21 /* at normal HCI mode */
-
-/* ioctl */
-#define PN544_CHAR_BASE                'P'
-#define PN544_IOR(num, dtype)  _IOR(PN544_CHAR_BASE, num, dtype)
-#define PN544_IOW(num, dtype)  _IOW(PN544_CHAR_BASE, num, dtype)
-#define PN544_GET_FW_MODE      PN544_IOW(1, unsigned int)
-#define PN544_SET_FW_MODE      PN544_IOW(2, unsigned int)
-#define PN544_GET_DEBUG                PN544_IOW(3, unsigned int)
-#define PN544_SET_DEBUG                PN544_IOW(4, unsigned int)
-
-/* Timing restrictions (ms) */
-#define PN544_RESETVEN_TIME    30 /* 7 */
-#define PN544_PVDDVEN_TIME     0
-#define PN544_VBATVEN_TIME     0
-#define PN544_GPIO4VEN_TIME    0
-#define PN544_WAKEUP_ACK       5
-#define PN544_WAKEUP_GUARD     (PN544_WAKEUP_ACK + 1)
-#define PN544_INACTIVITY_TIME  1000
-#define PN544_INTERFRAME_DELAY 200 /* us */
-#define PN544_BAUDRATE_CHANGE  150 /* us */
-
-/* Debug bits */
-#define PN544_DEBUG_BUF                0x01
-#define PN544_DEBUG_READ       0x02
-#define PN544_DEBUG_WRITE      0x04
-#define PN544_DEBUG_IRQ                0x08
-#define PN544_DEBUG_CALLS      0x10
-#define PN544_DEBUG_MODE       0x20
-
-/* Normal (HCI) mode */
-#define PN544_LLC_HCI_OVERHEAD 3 /* header + crc (to length) */
-#define PN544_LLC_MIN_SIZE     (1 + PN544_LLC_HCI_OVERHEAD) /* length + */
-#define PN544_LLC_MAX_DATA     (PN544_MSG_MAX_SIZE - 2)
-#define PN544_LLC_MAX_HCI_SIZE (PN544_LLC_MAX_DATA - 2)
-
-struct pn544_llc_packet {
-       unsigned char length; /* of rest of packet */
-       unsigned char header;
-       unsigned char data[PN544_LLC_MAX_DATA]; /* includes crc-ccitt */
-};
-
-/* Firmware upgrade mode */
-#define PN544_FW_HEADER_SIZE   3
-/* max fw transfer is 1024bytes, but I2C limits it to 0xC0 */
-#define PN544_MAX_FW_DATA      (PN544_MAX_I2C_TRANSFER - PN544_FW_HEADER_SIZE)
-
-struct pn544_fw_packet {
-       unsigned char command; /* status in answer */
-       unsigned char length[2]; /* big-endian order (msf) */
-       unsigned char data[PN544_MAX_FW_DATA];
-};
-
-#ifdef __KERNEL__
-enum {
-       NFC_GPIO_ENABLE,
-       NFC_GPIO_FW_RESET,
-       NFC_GPIO_IRQ
-};
-
-/* board config */
-struct pn544_nfc_platform_data {
-       int (*request_resources) (struct i2c_client *client);
-       void (*free_resources) (void);
-       void (*enable) (int fw);
-       int (*test) (void);
-       void (*disable) (void);
-       int (*get_gpio)(int type);
-};
-#endif /* __KERNEL__ */
-
-#endif /* _PN544_H_ */
diff --git a/include/linux/platform_data/pn544.h b/include/linux/platform_data/pn544.h
new file mode 100644 (file)
index 0000000..713bfd7
--- /dev/null
@@ -0,0 +1,44 @@
+/*
+ * Driver include for the PN544 NFC chip.
+ *
+ * Copyright (C) Nokia Corporation
+ *
+ * Author: Jari Vanhala <ext-jari.vanhala@nokia.com>
+ * Contact: Matti Aaltoenn <matti.j.aaltonen@nokia.com>
+ *
+ * This program is free software; you can redistribute it and/or
+ * modify it under the terms of the GNU General Public License
+ * version 2 as published by the Free Software Foundation.
+ *
+ * This program is distributed in the hope that it will be useful,
+ * but WITHOUT ANY WARRANTY; without even the implied warranty of
+ * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.        See the
+ * GNU General Public License for more details.
+ *
+ * You should have received a copy of the GNU General Public License
+ * along with this program; if not, write to the Free Software
+ * Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
+ */
+
+#ifndef _PN544_H_
+#define _PN544_H_
+
+#include <linux/i2c.h>
+
+enum {
+       NFC_GPIO_ENABLE,
+       NFC_GPIO_FW_RESET,
+       NFC_GPIO_IRQ
+};
+
+/* board config */
+struct pn544_nfc_platform_data {
+       int (*request_resources) (struct i2c_client *client);
+       void (*free_resources) (void);
+       void (*enable) (int fw);
+       int (*test) (void);
+       void (*disable) (void);
+       int (*get_gpio)(int type);
+};
+
+#endif /* _PN544_H_ */
index a0525019e1d1b9fdb703ed4ad1483b878ff0ee55..6ecfa02ddbac9e4917725938efca0ca37b07da64 100644 (file)
 #define  SSB_SPROM8_HWIQ_IQSWP_IQCAL_SWP_SHIFT 4
 #define  SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL        0x0020
 #define  SSB_SPROM8_HWIQ_IQSWP_HW_IQCAL_SHIFT  5
-#define SSB_SPROM8_TEMPDELTA           0x00BA
+#define SSB_SPROM8_TEMPDELTA           0x00BC
 #define  SSB_SPROM8_TEMPDELTA_PHYCAL   0x00ff
 #define  SSB_SPROM8_TEMPDELTA_PHYCAL_SHIFT     0
 #define  SSB_SPROM8_TEMPDELTA_PERIOD   0x0f00
index 2e7c79ea0463f0f03a7602f5269af7c18b7d6614..7ea3db77ba890a18876fd3a57ddf6aa27fa9269c 100644 (file)
@@ -46,5 +46,9 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
                        struct hci_conn *hcon);
 void amp_write_remote_assoc(struct hci_dev *hdev, u8 handle);
 void amp_write_rem_assoc_continue(struct hci_dev *hdev, u8 handle);
+void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon);
+void amp_create_logical_link(struct l2cap_chan *chan);
+void amp_disconnect_logical_link(struct hci_chan *hchan);
+void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason);
 
 #endif /* __AMP_H */
index 88cbbda6102777eb67e1ae33fbec458f17aec918..45eee08157bb926b316519da7cbba8cae49d2e71 100644 (file)
@@ -115,6 +115,7 @@ enum {
        HCI_SSP_ENABLED,
        HCI_HS_ENABLED,
        HCI_LE_ENABLED,
+       HCI_LE_PERIPHERAL,
        HCI_CONNECTABLE,
        HCI_DISCOVERABLE,
        HCI_LINK_SECURITY,
@@ -153,7 +154,7 @@ enum {
 #define HCI_DISCONN_TIMEOUT    msecs_to_jiffies(2000)  /* 2 seconds */
 #define HCI_PAIRING_TIMEOUT    msecs_to_jiffies(60000) /* 60 seconds */
 #define HCI_INIT_TIMEOUT       msecs_to_jiffies(10000) /* 10 seconds */
-#define HCI_CMD_TIMEOUT                msecs_to_jiffies(1000)  /* 1 second */
+#define HCI_CMD_TIMEOUT                msecs_to_jiffies(2000)  /* 2 seconds */
 #define HCI_ACL_TX_TIMEOUT     msecs_to_jiffies(45000) /* 45 seconds */
 #define HCI_AUTO_OFF_TIMEOUT   msecs_to_jiffies(2000)  /* 2 seconds */
 
@@ -318,6 +319,9 @@ enum {
 #define HCI_FLOW_CTL_MODE_PACKET_BASED 0x00
 #define HCI_FLOW_CTL_MODE_BLOCK_BASED  0x01
 
+/* The core spec defines 127 as the "not available" value */
+#define HCI_TX_POWER_INVALID   127
+
 /* Extended Inquiry Response field types */
 #define EIR_FLAGS              0x01 /* flags */
 #define EIR_UUID16_SOME                0x02 /* 16-bit UUID, more available */
@@ -334,6 +338,13 @@ enum {
 #define EIR_SSP_RAND_R         0x0F /* Simple Pairing Randomizer R */
 #define EIR_DEVICE_ID          0x10 /* device ID */
 
+/* Low Energy Advertising Flags */
+#define LE_AD_LIMITED          0x01 /* Limited Discoverable */
+#define LE_AD_GENERAL          0x02 /* General Discoverable */
+#define LE_AD_NO_BREDR         0x04 /* BR/EDR not supported */
+#define LE_AD_SIM_LE_BREDR_CTRL        0x08 /* Simultaneous LE & BR/EDR Controller */
+#define LE_AD_SIM_LE_BREDR_HOST        0x10 /* Simultaneous LE & BR/EDR Host */
+
 /* -----  HCI Commands ---- */
 #define HCI_OP_NOP                     0x0000
 
@@ -932,6 +943,22 @@ struct hci_rp_le_read_buffer_size {
        __u8     le_max_pkt;
 } __packed;
 
+#define HCI_OP_LE_READ_ADV_TX_POWER    0x2007
+struct hci_rp_le_read_adv_tx_power {
+       __u8    status;
+       __s8    tx_power;
+} __packed;
+
+#define HCI_MAX_AD_LENGTH              31
+
+#define HCI_OP_LE_SET_ADV_DATA         0x2008
+struct hci_cp_le_set_adv_data {
+       __u8    length;
+       __u8    data[HCI_MAX_AD_LENGTH];
+} __packed;
+
+#define HCI_OP_LE_SET_ADV_ENABLE       0x200a
+
 #define HCI_OP_LE_SET_SCAN_PARAM       0x200b
 struct hci_cp_le_set_scan_param {
        __u8    type;
index 9fe8e2dec870c57073d24aaf1b0ff6ebfbfc1801..ef5b85dac3f77720c13ba69a6482b58a3043c018 100644 (file)
@@ -278,6 +278,10 @@ struct hci_dev {
        struct work_struct      le_scan;
        struct le_scan_params   le_scan_params;
 
+       __s8                    adv_tx_power;
+       __u8                    adv_data[HCI_MAX_AD_LENGTH];
+       __u8                    adv_data_len;
+
        int (*open)(struct hci_dev *hdev);
        int (*close)(struct hci_dev *hdev);
        int (*flush)(struct hci_dev *hdev);
@@ -355,6 +359,7 @@ struct hci_chan {
        struct hci_conn *conn;
        struct sk_buff_head data_q;
        unsigned int    sent;
+       __u8            state;
 };
 
 extern struct list_head hci_dev_list;
@@ -682,7 +687,7 @@ static inline uint8_t __hci_num_ctrl(void)
 }
 
 struct hci_dev *hci_dev_get(int index);
-struct hci_dev *hci_get_route(bdaddr_t *src, bdaddr_t *dst);
+struct hci_dev *hci_get_route(bdaddr_t *dst, bdaddr_t *src);
 
 struct hci_dev *hci_alloc_dev(void);
 void hci_free_dev(struct hci_dev *hdev);
@@ -731,6 +736,8 @@ int hci_add_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 *hash,
                                                                u8 *randomizer);
 int hci_remove_remote_oob_data(struct hci_dev *hdev, bdaddr_t *bdaddr);
 
+int hci_update_ad(struct hci_dev *hdev);
+
 void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb);
 
 int hci_recv_frame(struct sk_buff *skb);
@@ -747,18 +754,29 @@ void hci_conn_del_sysfs(struct hci_conn *conn);
 #define SET_HCIDEV_DEV(hdev, pdev) ((hdev)->dev.parent = (pdev))
 
 /* ----- LMP capabilities ----- */
-#define lmp_rswitch_capable(dev)   ((dev)->features[0] & LMP_RSWITCH)
 #define lmp_encrypt_capable(dev)   ((dev)->features[0] & LMP_ENCRYPT)
+#define lmp_rswitch_capable(dev)   ((dev)->features[0] & LMP_RSWITCH)
+#define lmp_hold_capable(dev)      ((dev)->features[0] & LMP_HOLD)
 #define lmp_sniff_capable(dev)     ((dev)->features[0] & LMP_SNIFF)
-#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
+#define lmp_park_capable(dev)      ((dev)->features[1] & LMP_PARK)
+#define lmp_inq_rssi_capable(dev)  ((dev)->features[3] & LMP_RSSI_INQ)
 #define lmp_esco_capable(dev)      ((dev)->features[3] & LMP_ESCO)
+#define lmp_bredr_capable(dev)     (!((dev)->features[4] & LMP_NO_BREDR))
+#define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE)
+#define lmp_sniffsubr_capable(dev) ((dev)->features[5] & LMP_SNIFF_SUBR)
+#define lmp_pause_enc_capable(dev) ((dev)->features[5] & LMP_PAUSE_ENC)
+#define lmp_ext_inq_capable(dev)   ((dev)->features[6] & LMP_EXT_INQ)
+#define lmp_le_br_capable(dev)     ((dev)->features[6] & LMP_SIMUL_LE_BR)
 #define lmp_ssp_capable(dev)       ((dev)->features[6] & LMP_SIMPLE_PAIR)
 #define lmp_no_flush_capable(dev)  ((dev)->features[6] & LMP_NO_FLUSH)
-#define lmp_le_capable(dev)        ((dev)->features[4] & LMP_LE)
-#define lmp_bredr_capable(dev)     (!((dev)->features[4] & LMP_NO_BREDR))
+#define lmp_lsto_capable(dev)      ((dev)->features[7] & LMP_LSTO)
+#define lmp_inq_tx_pwr_capable(dev) ((dev)->features[7] & LMP_INQ_TX_PWR)
+#define lmp_ext_feat_capable(dev)  ((dev)->features[7] & LMP_EXTFEATURES)
 
 /* ----- Extended LMP capabilities ----- */
+#define lmp_host_ssp_capable(dev)  ((dev)->host_features[0] & LMP_HOST_SSP)
 #define lmp_host_le_capable(dev)   ((dev)->host_features[0] & LMP_HOST_LE)
+#define lmp_host_le_br_capable(dev) ((dev)->host_features[0] & LMP_HOST_LE_BREDR)
 
 /* ----- HCI protocols ----- */
 static inline int hci_proto_connect_ind(struct hci_dev *hdev, bdaddr_t *bdaddr,
@@ -877,7 +895,7 @@ struct hci_cb {
 
 static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
 {
-       struct list_head *p;
+       struct hci_cb *cb;
        __u8 encrypt;
 
        hci_proto_auth_cfm(conn, status);
@@ -888,8 +906,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
        encrypt = (conn->link_mode & HCI_LM_ENCRYPT) ? 0x01 : 0x00;
 
        read_lock(&hci_cb_list_lock);
-       list_for_each(p, &hci_cb_list) {
-               struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+       list_for_each_entry(cb, &hci_cb_list, list) {
                if (cb->security_cfm)
                        cb->security_cfm(conn, status, encrypt);
        }
@@ -899,7 +916,7 @@ static inline void hci_auth_cfm(struct hci_conn *conn, __u8 status)
 static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
                                                                __u8 encrypt)
 {
-       struct list_head *p;
+       struct hci_cb *cb;
 
        if (conn->sec_level == BT_SECURITY_SDP)
                conn->sec_level = BT_SECURITY_LOW;
@@ -910,8 +927,7 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
        hci_proto_encrypt_cfm(conn, status, encrypt);
 
        read_lock(&hci_cb_list_lock);
-       list_for_each(p, &hci_cb_list) {
-               struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+       list_for_each_entry(cb, &hci_cb_list, list) {
                if (cb->security_cfm)
                        cb->security_cfm(conn, status, encrypt);
        }
@@ -920,11 +936,10 @@ static inline void hci_encrypt_cfm(struct hci_conn *conn, __u8 status,
 
 static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
 {
-       struct list_head *p;
+       struct hci_cb *cb;
 
        read_lock(&hci_cb_list_lock);
-       list_for_each(p, &hci_cb_list) {
-               struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+       list_for_each_entry(cb, &hci_cb_list, list) {
                if (cb->key_change_cfm)
                        cb->key_change_cfm(conn, status);
        }
@@ -934,11 +949,10 @@ static inline void hci_key_change_cfm(struct hci_conn *conn, __u8 status)
 static inline void hci_role_switch_cfm(struct hci_conn *conn, __u8 status,
                                                                __u8 role)
 {
-       struct list_head *p;
+       struct hci_cb *cb;
 
        read_lock(&hci_cb_list_lock);
-       list_for_each(p, &hci_cb_list) {
-               struct hci_cb *cb = list_entry(p, struct hci_cb, list);
+       list_for_each_entry(cb, &hci_cb_list, list) {
                if (cb->role_switch_cfm)
                        cb->role_switch_cfm(conn, status, role);
        }
index 6e23afdf65c1c64a625c6763a1144383ccc5341d..f57fab04e7c5ff8b77c2c06eb92fd8dddcbf0f97 100644 (file)
@@ -52,6 +52,8 @@
 #define L2CAP_ENC_TIMEOUT              msecs_to_jiffies(5000)
 #define L2CAP_CONN_TIMEOUT             msecs_to_jiffies(40000)
 #define L2CAP_INFO_TIMEOUT             msecs_to_jiffies(4000)
+#define L2CAP_MOVE_TIMEOUT             msecs_to_jiffies(4000)
+#define L2CAP_MOVE_ERTX_TIMEOUT                msecs_to_jiffies(60000)
 
 #define L2CAP_A2MP_DEFAULT_MTU         670
 
@@ -434,6 +436,8 @@ struct l2cap_chan {
        struct sock *sk;
 
        struct l2cap_conn       *conn;
+       struct hci_conn         *hs_hcon;
+       struct hci_chan         *hs_hchan;
        struct kref     kref;
 
        __u8            state;
@@ -477,6 +481,12 @@ struct l2cap_chan {
        unsigned long   conn_state;
        unsigned long   flags;
 
+       __u8            remote_amp_id;
+       __u8            local_amp_id;
+       __u8            move_id;
+       __u8            move_state;
+       __u8            move_role;
+
        __u16           next_tx_seq;
        __u16           expected_ack_seq;
        __u16           expected_tx_seq;
@@ -509,8 +519,6 @@ struct l2cap_chan {
        __u32           remote_acc_lat;
        __u32           remote_flush_to;
 
-       __u8            ctrl_id;
-
        struct delayed_work     chan_timer;
        struct delayed_work     retrans_timer;
        struct delayed_work     monitor_timer;
@@ -644,6 +652,9 @@ enum {
 enum {
        L2CAP_RX_STATE_RECV,
        L2CAP_RX_STATE_SREJ_SENT,
+       L2CAP_RX_STATE_MOVE,
+       L2CAP_RX_STATE_WAIT_P,
+       L2CAP_RX_STATE_WAIT_F,
 };
 
 enum {
@@ -674,6 +685,25 @@ enum {
        L2CAP_EV_RECV_FRAME,
 };
 
+enum {
+       L2CAP_MOVE_ROLE_NONE,
+       L2CAP_MOVE_ROLE_INITIATOR,
+       L2CAP_MOVE_ROLE_RESPONDER,
+};
+
+enum {
+       L2CAP_MOVE_STABLE,
+       L2CAP_MOVE_WAIT_REQ,
+       L2CAP_MOVE_WAIT_RSP,
+       L2CAP_MOVE_WAIT_RSP_SUCCESS,
+       L2CAP_MOVE_WAIT_CONFIRM,
+       L2CAP_MOVE_WAIT_CONFIRM_RSP,
+       L2CAP_MOVE_WAIT_LOGICAL_COMP,
+       L2CAP_MOVE_WAIT_LOGICAL_CFM,
+       L2CAP_MOVE_WAIT_LOCAL_BUSY,
+       L2CAP_MOVE_WAIT_PREPARE,
+};
+
 void l2cap_chan_hold(struct l2cap_chan *c);
 void l2cap_chan_put(struct l2cap_chan *c);
 
@@ -778,5 +808,9 @@ void l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void __l2cap_chan_add(struct l2cap_conn *conn, struct l2cap_chan *chan);
 void l2cap_chan_del(struct l2cap_chan *chan, int err);
 void l2cap_send_conn_req(struct l2cap_chan *chan);
+void l2cap_move_start(struct l2cap_chan *chan);
+void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
+                      u8 status);
+void __l2cap_physical_cfm(struct l2cap_chan *chan, int result);
 
 #endif /* __L2CAP_H */
index c6964572890ffe2407d88deb2f83c15bb97719ad..e78db2cf3d1b2f40fd49b345036bf89d7885bcc6 100644 (file)
@@ -305,6 +305,88 @@ struct key_params {
        u32 cipher;
 };
 
+/**
+ * struct cfg80211_chan_def - channel definition
+ * @chan: the (control) channel
+ * @width: channel width
+ * @center_freq1: center frequency of first segment
+ * @center_freq2: center frequency of second segment
+ *     (only with 80+80 MHz)
+ */
+struct cfg80211_chan_def {
+       struct ieee80211_channel *chan;
+       enum nl80211_chan_width width;
+       u32 center_freq1;
+       u32 center_freq2;
+};
+
+/**
+ * cfg80211_get_chandef_type - return old channel type from chandef
+ * @chandef: the channel definition
+ *
+ * Returns the old channel type (NOHT, HT20, HT40+/-) from a given
+ * chandef, which must have a bandwidth allowing this conversion.
+ */
+static inline enum nl80211_channel_type
+cfg80211_get_chandef_type(const struct cfg80211_chan_def *chandef)
+{
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               return NL80211_CHAN_NO_HT;
+       case NL80211_CHAN_WIDTH_20:
+               return NL80211_CHAN_HT20;
+       case NL80211_CHAN_WIDTH_40:
+               if (chandef->center_freq1 > chandef->chan->center_freq)
+                       return NL80211_CHAN_HT40PLUS;
+               return NL80211_CHAN_HT40MINUS;
+       default:
+               WARN_ON(1);
+               return NL80211_CHAN_NO_HT;
+       }
+}
+
+/**
+ * cfg80211_chandef_create - create channel definition using channel type
+ * @chandef: the channel definition struct to fill
+ * @channel: the control channel
+ * @chantype: the channel type
+ *
+ * Given a channel type, create a channel definition.
+ */
+void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
+                            struct ieee80211_channel *channel,
+                            enum nl80211_channel_type chantype);
+
+/**
+ * cfg80211_chandef_identical - check if two channel definitions are identical
+ * @chandef1: first channel definition
+ * @chandef2: second channel definition
+ *
+ * Returns %true if the channels defined by the channel definitions are
+ * identical, %false otherwise.
+ */
+static inline bool
+cfg80211_chandef_identical(const struct cfg80211_chan_def *chandef1,
+                          const struct cfg80211_chan_def *chandef2)
+{
+       return (chandef1->chan == chandef2->chan &&
+               chandef1->width == chandef2->width &&
+               chandef1->center_freq1 == chandef2->center_freq1 &&
+               chandef1->center_freq2 == chandef2->center_freq2);
+}
+
+/**
+ * cfg80211_chandef_compatible - check if two channel definitions are compatible
+ * @chandef1: first channel definition
+ * @chandef2: second channel definition
+ *
+ * Returns %NULL if the given channel definitions are incompatible,
+ * chandef1 or chandef2 otherwise.
+ */
+const struct cfg80211_chan_def *
+cfg80211_chandef_compatible(const struct cfg80211_chan_def *chandef1,
+                           const struct cfg80211_chan_def *chandef2);
+
 /**
  * enum survey_info_flags - survey information flags
  *
@@ -426,8 +508,7 @@ struct cfg80211_beacon_data {
  *
  * Used to configure an AP interface.
  *
- * @channel: the channel to start the AP on
- * @channel_type: the channel type to use
+ * @chandef: defines the channel to use
  * @beacon: beacon data
  * @beacon_interval: beacon interval
  * @dtim_period: DTIM period
@@ -441,8 +522,7 @@ struct cfg80211_beacon_data {
  * @inactivity_timeout: time in seconds to determine station's inactivity.
  */
 struct cfg80211_ap_settings {
-       struct ieee80211_channel *channel;
-       enum nl80211_channel_type channel_type;
+       struct cfg80211_chan_def chandef;
 
        struct cfg80211_beacon_data beacon;
 
@@ -582,16 +662,24 @@ enum station_info_flags {
  * Used by the driver to indicate the specific rate transmission
  * type for 802.11n transmissions.
  *
- * @RATE_INFO_FLAGS_MCS: @tx_bitrate_mcs filled
- * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 Mhz width transmission
+ * @RATE_INFO_FLAGS_MCS: mcs field filled with HT MCS
+ * @RATE_INFO_FLAGS_VHT_MCS: mcs field filled with VHT MCS
+ * @RATE_INFO_FLAGS_40_MHZ_WIDTH: 40 MHz width transmission
+ * @RATE_INFO_FLAGS_80_MHZ_WIDTH: 80 MHz width transmission
+ * @RATE_INFO_FLAGS_80P80_MHZ_WIDTH: 80+80 MHz width transmission
+ * @RATE_INFO_FLAGS_160_MHZ_WIDTH: 160 MHz width transmission
  * @RATE_INFO_FLAGS_SHORT_GI: 400ns guard interval
- * @RATE_INFO_FLAGS_60G: 60gHz MCS
+ * @RATE_INFO_FLAGS_60G: 60GHz MCS
  */
 enum rate_info_flags {
-       RATE_INFO_FLAGS_MCS             = 1<<0,
-       RATE_INFO_FLAGS_40_MHZ_WIDTH    = 1<<1,
-       RATE_INFO_FLAGS_SHORT_GI        = 1<<2,
-       RATE_INFO_FLAGS_60G             = 1<<3,
+       RATE_INFO_FLAGS_MCS                     = BIT(0),
+       RATE_INFO_FLAGS_VHT_MCS                 = BIT(1),
+       RATE_INFO_FLAGS_40_MHZ_WIDTH            = BIT(2),
+       RATE_INFO_FLAGS_80_MHZ_WIDTH            = BIT(3),
+       RATE_INFO_FLAGS_80P80_MHZ_WIDTH         = BIT(4),
+       RATE_INFO_FLAGS_160_MHZ_WIDTH           = BIT(5),
+       RATE_INFO_FLAGS_SHORT_GI                = BIT(6),
+       RATE_INFO_FLAGS_60G                     = BIT(7),
 };
 
 /**
@@ -602,11 +690,13 @@ enum rate_info_flags {
  * @flags: bitflag of flags from &enum rate_info_flags
  * @mcs: mcs index if struct describes a 802.11n bitrate
  * @legacy: bitrate in 100kbit/s for 802.11abg
+ * @nss: number of streams (VHT only)
  */
 struct rate_info {
        u8 flags;
        u8 mcs;
        u16 legacy;
+       u8 nss;
 };
 
 /**
@@ -909,8 +999,7 @@ struct mesh_config {
 
 /**
  * struct mesh_setup - 802.11s mesh setup configuration
- * @channel: the channel to start the mesh network on
- * @channel_type: the channel type to use
+ * @chandef: defines the channel to use
  * @mesh_id: the mesh ID
  * @mesh_id_len: length of the mesh ID, at least 1 and at most 32 bytes
  * @sync_method: which synchronization method to use
@@ -925,8 +1014,7 @@ struct mesh_config {
  * These parameters are fixed when the mesh is created.
  */
 struct mesh_setup {
-       struct ieee80211_channel *channel;
-       enum nl80211_channel_type channel_type;
+       struct cfg80211_chan_def chandef;
        const u8 *mesh_id;
        u8 mesh_id_len;
        u8 sync_method;
@@ -1266,8 +1354,7 @@ struct cfg80211_disassoc_request {
  * @ssid_len: The length of the SSID, will always be non-zero.
  * @bssid: Fixed BSSID requested, maybe be %NULL, if set do not
  *     search for IBSSs with a different BSSID.
- * @channel: The channel to use if no IBSS can be found to join.
- * @channel_type: channel type (HT mode)
+ * @chandef: defines the channel to use if no other IBSS to join can be found
  * @channel_fixed: The channel should be fixed -- do not search for
  *     IBSSs to join on other channels.
  * @ie: information element(s) to include in the beacon
@@ -1285,8 +1372,7 @@ struct cfg80211_disassoc_request {
 struct cfg80211_ibss_params {
        u8 *ssid;
        u8 *bssid;
-       struct ieee80211_channel *channel;
-       enum nl80211_channel_type channel_type;
+       struct cfg80211_chan_def chandef;
        u8 *ie;
        u8 ssid_len, ie_len;
        u16 beacon_interval;
@@ -1545,13 +1631,19 @@ struct cfg80211_gtk_rekey_data {
  *     to a merge.
  * @leave_ibss: Leave the IBSS.
  *
+ * @set_mcast_rate: Set the specified multicast rate (only if vif is in ADHOC or
+ *     MESH mode)
+ *
  * @set_wiphy_params: Notify that wiphy parameters have changed;
  *     @changed bitfield (see &enum wiphy_params_flags) describes which values
  *     have changed. The actual parameter values are available in
  *     struct wiphy. If returning an error, no value should be changed.
  *
  * @set_tx_power: set the transmit power according to the parameters,
- *     the power passed is in mBm, to get dBm use MBM_TO_DBM().
+ *     the power passed is in mBm, to get dBm use MBM_TO_DBM(). The
+ *     wdev may be %NULL if power was set for the wiphy, and will
+ *     always be %NULL unless the driver supports per-vif TX power
+ *     (as advertised by the nl80211 feature flag.)
  * @get_tx_power: store the current TX power into the dbm variable;
  *     return 0 if successful
  *
@@ -1722,8 +1814,7 @@ struct cfg80211_ops {
                                             struct ieee80211_channel *chan);
 
        int     (*set_monitor_channel)(struct wiphy *wiphy,
-                                      struct ieee80211_channel *chan,
-                                      enum nl80211_channel_type channel_type);
+                                      struct cfg80211_chan_def *chandef);
 
        int     (*scan)(struct wiphy *wiphy,
                        struct cfg80211_scan_request *request);
@@ -1746,11 +1837,15 @@ struct cfg80211_ops {
                             struct cfg80211_ibss_params *params);
        int     (*leave_ibss)(struct wiphy *wiphy, struct net_device *dev);
 
+       int     (*set_mcast_rate)(struct wiphy *wiphy, struct net_device *dev,
+                                 int rate[IEEE80211_NUM_BANDS]);
+
        int     (*set_wiphy_params)(struct wiphy *wiphy, u32 changed);
 
-       int     (*set_tx_power)(struct wiphy *wiphy,
+       int     (*set_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
                                enum nl80211_tx_power_setting type, int mbm);
-       int     (*get_tx_power)(struct wiphy *wiphy, int *dbm);
+       int     (*get_tx_power)(struct wiphy *wiphy, struct wireless_dev *wdev,
+                               int *dbm);
 
        int     (*set_wds_peer)(struct wiphy *wiphy, struct net_device *dev,
                                const u8 *addr);
@@ -1781,7 +1876,6 @@ struct cfg80211_ops {
        int     (*remain_on_channel)(struct wiphy *wiphy,
                                     struct wireless_dev *wdev,
                                     struct ieee80211_channel *chan,
-                                    enum nl80211_channel_type channel_type,
                                     unsigned int duration,
                                     u64 *cookie);
        int     (*cancel_remain_on_channel)(struct wiphy *wiphy,
@@ -1790,10 +1884,8 @@ struct cfg80211_ops {
 
        int     (*mgmt_tx)(struct wiphy *wiphy, struct wireless_dev *wdev,
                          struct ieee80211_channel *chan, bool offchan,
-                         enum nl80211_channel_type channel_type,
-                         bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, bool no_cck,
-                         bool dont_wait_for_ack, u64 *cookie);
+                         unsigned int wait, const u8 *buf, size_t len,
+                         bool no_cck, bool dont_wait_for_ack, u64 *cookie);
        int     (*mgmt_tx_cancel_wait)(struct wiphy *wiphy,
                                       struct wireless_dev *wdev,
                                       u64 cookie);
@@ -1848,10 +1940,9 @@ struct cfg80211_ops {
        void    (*get_et_strings)(struct wiphy *wiphy, struct net_device *dev,
                                  u32 sset, u8 *data);
 
-       struct ieee80211_channel *
-               (*get_channel)(struct wiphy *wiphy,
+       int     (*get_channel)(struct wiphy *wiphy,
                               struct wireless_dev *wdev,
-                              enum nl80211_channel_type *type);
+                              struct cfg80211_chan_def *chandef);
 
        int     (*start_p2p_device)(struct wiphy *wiphy,
                                    struct wireless_dev *wdev);
@@ -2459,8 +2550,7 @@ struct wireless_dev {
        spinlock_t event_lock;
 
        struct cfg80211_internal_bss *current_bss; /* associated / joined */
-       struct ieee80211_channel *preset_chan;
-       enum nl80211_channel_type preset_chantype;
+       struct cfg80211_chan_def preset_chandef;
 
        /* for AP and mesh channel tracking */
        struct ieee80211_channel *channel;
@@ -3340,14 +3430,12 @@ void cfg80211_disconnected(struct net_device *dev, u16 reason,
  * @wdev: wireless device
  * @cookie: the request cookie
  * @chan: The current channel (from remain_on_channel request)
- * @channel_type: Channel type
  * @duration: Duration in milliseconds that the driver intents to remain on the
  *     channel
  * @gfp: allocation flags
  */
 void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
                               struct ieee80211_channel *chan,
-                              enum nl80211_channel_type channel_type,
                               unsigned int duration, gfp_t gfp);
 
 /**
@@ -3355,12 +3443,10 @@ void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
  * @wdev: wireless device
  * @cookie: the request cookie
  * @chan: The current channel (from remain_on_channel request)
- * @channel_type: Channel type
  * @gfp: allocation flags
  */
 void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
                                        struct ieee80211_channel *chan,
-                                       enum nl80211_channel_type channel_type,
                                        gfp_t gfp);
 
 
@@ -3550,7 +3636,6 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
  * @len: length of the frame
  * @freq: frequency the frame was received on
  * @sig_dbm: signal strength in mBm, or 0 if unknown
- * @gfp: allocation flags
  *
  * Use this function to report to userspace when a beacon was
  * received. It is not useful to call this when there is no
@@ -3558,31 +3643,47 @@ void cfg80211_probe_status(struct net_device *dev, const u8 *addr,
  */
 void cfg80211_report_obss_beacon(struct wiphy *wiphy,
                                 const u8 *frame, size_t len,
-                                int freq, int sig_dbm, gfp_t gfp);
+                                int freq, int sig_dbm);
 
 /**
- * cfg80211_can_beacon_sec_chan - test if ht40 on extension channel can be used
+ * cfg80211_reg_can_beacon - check if beaconing is allowed
  * @wiphy: the wiphy
- * @chan: main channel
- * @channel_type: HT mode
+ * @chandef: the channel definition
  *
  * This function returns true if there is no secondary channel or the secondary
- * channel can be used for beaconing (i.e. is not a radar channel etc.)
+ * channel(s) can be used for beaconing (i.e. is not a radar channel etc.)
  */
-bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
-                                 struct ieee80211_channel *chan,
-                                 enum nl80211_channel_type channel_type);
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+                            struct cfg80211_chan_def *chandef);
 
 /*
  * cfg80211_ch_switch_notify - update wdev channel and notify userspace
  * @dev: the device which switched channels
- * @freq: new channel frequency (in MHz)
- * @type: channel type
+ * @chandef: the new channel definition
  *
  * Acquires wdev_lock, so must only be called from sleepable driver context!
  */
-void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
-                              enum nl80211_channel_type type);
+void cfg80211_ch_switch_notify(struct net_device *dev,
+                              struct cfg80211_chan_def *chandef);
+
+/*
+ * cfg80211_tdls_oper_request - request userspace to perform TDLS operation
+ * @dev: the device on which the operation is requested
+ * @peer: the MAC address of the peer device
+ * @oper: the requested TDLS operation (NL80211_TDLS_SETUP or
+ *     NL80211_TDLS_TEARDOWN)
+ * @reason_code: the reason code for teardown request
+ * @gfp: allocation flags
+ *
+ * This function is used to request userspace to perform TDLS operation that
+ * requires knowledge of keys, i.e., link setup or teardown when the AP
+ * connection uses encryption. This is optional mechanism for the driver to use
+ * if it can automatically determine when a TDLS link could be useful (e.g.,
+ * based on traffic and signal strength for a peer).
+ */
+void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
+                               enum nl80211_tdls_operation oper,
+                               u16 reason_code, gfp_t gfp);
 
 /*
  * cfg80211_calculate_bitrate - calculate actual bitrate (in 100Kbps units)
@@ -3608,6 +3709,26 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate);
  */
 void cfg80211_unregister_wdev(struct wireless_dev *wdev);
 
+/**
+ * cfg80211_get_p2p_attr - find and copy a P2P attribute from IE buffer
+ * @ies: the input IE buffer
+ * @len: the input length
+ * @attr: the attribute ID to find
+ * @buf: output buffer, can be %NULL if the data isn't needed, e.g.
+ *     if the function is only called to get the needed buffer size
+ * @bufsize: size of the output buffer
+ *
+ * The function finds a given P2P attribute in the (vendor) IEs and
+ * copies its contents to the given buffer.
+ *
+ * The return value is a negative error code (-%EILSEQ or -%ENOENT) if
+ * the data is malformed or the attribute can't be found (respectively),
+ * or the length of the found attribute (which can be zero).
+ */
+int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
+                         enum ieee80211_p2p_attr_id attr,
+                         u8 *buf, unsigned int bufsize);
+
 /* Logging, debugging and troubleshooting/diagnostic helpers. */
 
 /* wiphy_printk helpers, similar to dev_printk */
index 00b7204708bd681d7bb8baf241b23557460f1a09..db7680acd0daafc9812a00c06eff55e07eabf835 100644 (file)
@@ -145,11 +145,11 @@ struct ieee80211_low_level_stats {
 
 /**
  * enum ieee80211_chanctx_change - change flag for channel context
- * @IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE: The channel type was changed
+ * @IEEE80211_CHANCTX_CHANGE_WIDTH: The channel width changed
  * @IEEE80211_CHANCTX_CHANGE_RX_CHAINS: The number of RX chains changed
  */
 enum ieee80211_chanctx_change {
-       IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE   = BIT(0),
+       IEEE80211_CHANCTX_CHANGE_WIDTH          = BIT(0),
        IEEE80211_CHANCTX_CHANGE_RX_CHAINS      = BIT(1),
 };
 
@@ -159,8 +159,7 @@ enum ieee80211_chanctx_change {
  * This is the driver-visible part. The ieee80211_chanctx
  * that contains it is visible in mac80211 only.
  *
- * @channel: the channel to tune to
- * @channel_type: the channel (HT) type
+ * @def: the channel definition
  * @rx_chains_static: The number of RX chains that must always be
  *     active on the channel to receive MIMO transmissions
  * @rx_chains_dynamic: The number of RX chains that must be enabled
@@ -170,8 +169,7 @@ enum ieee80211_chanctx_change {
  *     sizeof(void *), size is determined in hw information.
  */
 struct ieee80211_chanctx_conf {
-       struct ieee80211_channel *channel;
-       enum nl80211_channel_type channel_type;
+       struct cfg80211_chan_def def;
 
        u8 rx_chains_static, rx_chains_dynamic;
 
@@ -207,6 +205,9 @@ struct ieee80211_chanctx_conf {
  * @BSS_CHANGED_SSID: SSID changed for this BSS (AP mode)
  * @BSS_CHANGED_AP_PROBE_RESP: Probe Response changed for this BSS (AP mode)
  * @BSS_CHANGED_PS: PS changed for this BSS (STA mode)
+ * @BSS_CHANGED_TXPOWER: TX power setting changed for this interface
+ * @BSS_CHANGED_P2P_PS: P2P powersave settings (CTWindow, opportunistic PS)
+ *     changed (currently only in P2P client mode, GO mode will be later)
  */
 enum ieee80211_bss_change {
        BSS_CHANGED_ASSOC               = 1<<0,
@@ -227,6 +228,8 @@ enum ieee80211_bss_change {
        BSS_CHANGED_SSID                = 1<<15,
        BSS_CHANGED_AP_PROBE_RESP       = 1<<16,
        BSS_CHANGED_PS                  = 1<<17,
+       BSS_CHANGED_TXPOWER             = 1<<18,
+       BSS_CHANGED_P2P_PS              = 1<<19,
 
        /* when adding here, make sure to change ieee80211_reconfig */
 };
@@ -283,9 +286,8 @@ enum ieee80211_rssi_event {
  * @mcast_rate: per-band multicast rate index + 1 (0: disabled)
  * @bssid: The BSSID for this BSS
  * @enable_beacon: whether beaconing should be enabled or not
- * @channel_type: Channel type for this BSS -- the hardware might be
- *     configured for HT40+ while this BSS only uses no-HT, for
- *     example.
+ * @chandef: Channel definition for this BSS -- the hardware might be
+ *     configured a higher bandwidth than this BSS uses, for example.
  * @ht_operation_mode: HT operation mode like in &struct ieee80211_ht_operation.
  *     This field is only valid when the channel type is one of the HT types.
  * @cqm_rssi_thold: Connection quality monitor RSSI threshold, a zero value
@@ -309,6 +311,9 @@ enum ieee80211_rssi_event {
  * @ssid: The SSID of the current vif. Only valid in AP-mode.
  * @ssid_len: Length of SSID given in @ssid.
  * @hidden_ssid: The SSID of the current vif is hidden. Only valid in AP-mode.
+ * @txpower: TX power in dBm
+ * @p2p_ctwindow: P2P CTWindow, only for P2P client interfaces
+ * @p2p_oppps: P2P opportunistic PS is enabled
  */
 struct ieee80211_bss_conf {
        const u8 *bssid;
@@ -331,7 +336,7 @@ struct ieee80211_bss_conf {
        u16 ht_operation_mode;
        s32 cqm_rssi_thold;
        u32 cqm_rssi_hyst;
-       enum nl80211_channel_type channel_type;
+       struct cfg80211_chan_def chandef;
        __be32 arp_addr_list[IEEE80211_BSS_ARP_ADDR_LIST_LEN];
        u8 arp_addr_cnt;
        bool arp_filter_enabled;
@@ -341,6 +346,9 @@ struct ieee80211_bss_conf {
        u8 ssid[IEEE80211_MAX_SSID_LEN];
        size_t ssid_len;
        bool hidden_ssid;
+       int txpower;
+       u8 p2p_ctwindow;
+       bool p2p_oppps;
 };
 
 /**
@@ -491,9 +499,14 @@ enum mac80211_tx_control_flags {
  *     This is set if the current BSS requires ERP protection.
  * @IEEE80211_TX_RC_USE_SHORT_PREAMBLE: Use short preamble.
  * @IEEE80211_TX_RC_MCS: HT rate.
+ * @IEEE80211_TX_RC_VHT_MCS: VHT MCS rate, in this case the idx field is split
+ *     into a higher 4 bits (Nss) and lower 4 bits (MCS number)
  * @IEEE80211_TX_RC_GREEN_FIELD: Indicates whether this rate should be used in
  *     Greenfield mode.
  * @IEEE80211_TX_RC_40_MHZ_WIDTH: Indicates if the Channel Width should be 40 MHz.
+ * @IEEE80211_TX_RC_80_MHZ_WIDTH: Indicates 80 MHz transmission
+ * @IEEE80211_TX_RC_160_MHZ_WIDTH: Indicates 160 MHz transmission
+ *     (80+80 isn't supported yet)
  * @IEEE80211_TX_RC_DUP_DATA: The frame should be transmitted on both of the
  *     adjacent 20 MHz channels, if the current channel type is
  *     NL80211_CHAN_HT40MINUS or NL80211_CHAN_HT40PLUS.
@@ -504,12 +517,15 @@ enum mac80211_rate_control_flags {
        IEEE80211_TX_RC_USE_CTS_PROTECT         = BIT(1),
        IEEE80211_TX_RC_USE_SHORT_PREAMBLE      = BIT(2),
 
-       /* rate index is an MCS rate number instead of an index */
+       /* rate index is an HT/VHT MCS instead of an index */
        IEEE80211_TX_RC_MCS                     = BIT(3),
        IEEE80211_TX_RC_GREEN_FIELD             = BIT(4),
        IEEE80211_TX_RC_40_MHZ_WIDTH            = BIT(5),
        IEEE80211_TX_RC_DUP_DATA                = BIT(6),
        IEEE80211_TX_RC_SHORT_GI                = BIT(7),
+       IEEE80211_TX_RC_VHT_MCS                 = BIT(8),
+       IEEE80211_TX_RC_80_MHZ_WIDTH            = BIT(9),
+       IEEE80211_TX_RC_160_MHZ_WIDTH           = BIT(10),
 };
 
 
@@ -552,10 +568,32 @@ enum mac80211_rate_control_flags {
  */
 struct ieee80211_tx_rate {
        s8 idx;
-       u8 count;
-       u8 flags;
+       u16 count:5,
+           flags:11;
 } __packed;
 
+#define IEEE80211_MAX_TX_RETRY         31
+
+static inline void ieee80211_rate_set_vht(struct ieee80211_tx_rate *rate,
+                                         u8 mcs, u8 nss)
+{
+       WARN_ON(mcs & ~0xF);
+       WARN_ON(nss & ~0x7);
+       rate->idx = (nss << 4) | mcs;
+}
+
+static inline u8
+ieee80211_rate_get_vht_mcs(const struct ieee80211_tx_rate *rate)
+{
+       return rate->idx & 0xF;
+}
+
+static inline u8
+ieee80211_rate_get_vht_nss(const struct ieee80211_tx_rate *rate)
+{
+       return rate->idx >> 4;
+}
+
 /**
  * struct ieee80211_tx_info - skb transmit information
  *
@@ -700,13 +738,20 @@ ieee80211_tx_info_clear_status(struct ieee80211_tx_info *info)
  *     the frame.
  * @RX_FLAG_FAILED_PLCP_CRC: Set this flag if the PCLP check failed on
  *     the frame.
- * @RX_FLAG_MACTIME_MPDU: The timestamp passed in the RX status (@mactime
+ * @RX_FLAG_MACTIME_START: The timestamp passed in the RX status (@mactime
  *     field) is valid and contains the time the first symbol of the MPDU
  *     was received. This is useful in monitor mode and for proper IBSS
  *     merging.
+ * @RX_FLAG_MACTIME_END: The timestamp passed in the RX status (@mactime
+ *     field) is valid and contains the time the last symbol of the MPDU
+ *     (including FCS) was received.
  * @RX_FLAG_SHORTPRE: Short preamble was used for this frame
  * @RX_FLAG_HT: HT MCS was used and rate_idx is MCS index
+ * @RX_FLAG_VHT: VHT MCS was used and rate_index is MCS index
  * @RX_FLAG_40MHZ: HT40 (40 MHz) was used
+ * @RX_FLAG_80MHZ: 80 MHz was used
+ * @RX_FLAG_80P80MHZ: 80+80 MHz was used
+ * @RX_FLAG_160MHZ: 160 MHz was used
  * @RX_FLAG_SHORT_GI: Short guard interval was used
  * @RX_FLAG_NO_SIGNAL_VAL: The signal strength value is not present.
  *     Valid only for data frames (mainly A-MPDU)
@@ -734,7 +779,7 @@ enum mac80211_rx_flags {
        RX_FLAG_IV_STRIPPED             = BIT(4),
        RX_FLAG_FAILED_FCS_CRC          = BIT(5),
        RX_FLAG_FAILED_PLCP_CRC         = BIT(6),
-       RX_FLAG_MACTIME_MPDU            = BIT(7),
+       RX_FLAG_MACTIME_START           = BIT(7),
        RX_FLAG_SHORTPRE                = BIT(8),
        RX_FLAG_HT                      = BIT(9),
        RX_FLAG_40MHZ                   = BIT(10),
@@ -748,6 +793,11 @@ enum mac80211_rx_flags {
        RX_FLAG_AMPDU_IS_LAST           = BIT(18),
        RX_FLAG_AMPDU_DELIM_CRC_ERROR   = BIT(19),
        RX_FLAG_AMPDU_DELIM_CRC_KNOWN   = BIT(20),
+       RX_FLAG_MACTIME_END             = BIT(21),
+       RX_FLAG_VHT                     = BIT(22),
+       RX_FLAG_80MHZ                   = BIT(23),
+       RX_FLAG_80P80MHZ                = BIT(24),
+       RX_FLAG_160MHZ                  = BIT(25),
 };
 
 /**
@@ -768,25 +818,39 @@ enum mac80211_rx_flags {
  *     @IEEE80211_HW_SIGNAL_*
  * @antenna: antenna used
  * @rate_idx: index of data rate into band's supported rates or MCS index if
- *     HT rates are use (RX_FLAG_HT)
+ *     HT or VHT is used (%RX_FLAG_HT/%RX_FLAG_VHT)
+ * @vht_nss: number of streams (VHT only)
  * @flag: %RX_FLAG_*
  * @rx_flags: internal RX flags for mac80211
  * @ampdu_reference: A-MPDU reference number, must be a different value for
  *     each A-MPDU but the same for each subframe within one A-MPDU
  * @ampdu_delimiter_crc: A-MPDU delimiter CRC
+ * @vendor_radiotap_bitmap: radiotap vendor namespace presence bitmap
+ * @vendor_radiotap_len: radiotap vendor namespace length
+ * @vendor_radiotap_align: radiotap vendor namespace alignment. Note
+ *     that the actual data must be at the start of the SKB data
+ *     already.
+ * @vendor_radiotap_oui: radiotap vendor namespace OUI
+ * @vendor_radiotap_subns: radiotap vendor sub namespace
  */
 struct ieee80211_rx_status {
        u64 mactime;
        u32 device_timestamp;
        u32 ampdu_reference;
        u32 flag;
+       u32 vendor_radiotap_bitmap;
+       u16 vendor_radiotap_len;
        u16 freq;
        u8 rate_idx;
+       u8 vht_nss;
        u8 rx_flags;
        u8 band;
        u8 antenna;
        s8 signal;
        u8 ampdu_delimiter_crc;
+       u8 vendor_radiotap_align;
+       u8 vendor_radiotap_oui[3];
+       u8 vendor_radiotap_subns;
 };
 
 /**
@@ -884,7 +948,8 @@ enum ieee80211_smps_mode {
  *     powersave documentation below. This variable is valid only when
  *     the CONF_PS flag is set.
  *
- * @power_level: requested transmit power (in dBm)
+ * @power_level: requested transmit power (in dBm), backward compatibility
+ *     value only that is set to the minimum of all interfaces
  *
  * @channel: the channel to tune to
  * @channel_type: the channel (HT) type
@@ -2180,6 +2245,14 @@ enum ieee80211_rate_control_changed {
  * @sta_remove: Notifies low level driver about removal of an associated
  *     station, AP, IBSS/WDS/mesh peer etc. This callback can sleep.
  *
+ * @sta_add_debugfs: Drivers can use this callback to add debugfs files
+ *     when a station is added to mac80211's station list. This callback
+ *     and @sta_remove_debugfs should be within a CONFIG_MAC80211_DEBUGFS
+ *     conditional. This callback can sleep.
+ *
+ * @sta_remove_debugfs: Remove the debugfs files which were added using
+ *     @sta_add_debugfs. This callback can sleep.
+ *
  * @sta_notify: Notifies low level driver about power state transition of an
  *     associated station, AP,  IBSS/WDS/mesh peer etc. For a VIF operating
  *     in AP mode, this callback will not be called when the flag
@@ -2381,6 +2454,17 @@ enum ieee80211_rate_control_changed {
  *     to vif. Possible use is for hw queue remapping.
  * @unassign_vif_chanctx: Notifies device driver about channel context being
  *     unbound from vif.
+ * @start_ap: Start operation on the AP interface, this is called after all the
+ *     information in bss_conf is set and beacon can be retrieved. A channel
+ *     context is bound before this is called. Note that if the driver uses
+ *     software scan or ROC, this (and @stop_ap) isn't called when the AP is
+ *     just "paused" for scanning/ROC, which is indicated by the beacon being
+ *     disabled/enabled via @bss_info_changed.
+ * @stop_ap: Stop operation on the AP interface.
+ *
+ * @restart_complete: Called after a call to ieee80211_restart_hw(), when the
+ *     reconfiguration has completed. This can help the driver implement the
+ *     reconfiguration step. This callback may sleep.
  */
 struct ieee80211_ops {
        void (*tx)(struct ieee80211_hw *hw,
@@ -2406,6 +2490,9 @@ struct ieee80211_ops {
                                 struct ieee80211_bss_conf *info,
                                 u32 changed);
 
+       int (*start_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+       void (*stop_ap)(struct ieee80211_hw *hw, struct ieee80211_vif *vif);
+
        u64 (*prepare_multicast)(struct ieee80211_hw *hw,
                                 struct netdev_hw_addr_list *mc_list);
        void (*configure_filter)(struct ieee80211_hw *hw,
@@ -2447,6 +2534,16 @@ struct ieee80211_ops {
                       struct ieee80211_sta *sta);
        int (*sta_remove)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                          struct ieee80211_sta *sta);
+#ifdef CONFIG_MAC80211_DEBUGFS
+       void (*sta_add_debugfs)(struct ieee80211_hw *hw,
+                               struct ieee80211_vif *vif,
+                               struct ieee80211_sta *sta,
+                               struct dentry *dir);
+       void (*sta_remove_debugfs)(struct ieee80211_hw *hw,
+                                  struct ieee80211_vif *vif,
+                                  struct ieee80211_sta *sta,
+                                  struct dentry *dir);
+#endif
        void (*sta_notify)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
                        enum sta_notify_cmd, struct ieee80211_sta *sta);
        int (*sta_state)(struct ieee80211_hw *hw, struct ieee80211_vif *vif,
@@ -2488,8 +2585,8 @@ struct ieee80211_ops {
        int (*get_antenna)(struct ieee80211_hw *hw, u32 *tx_ant, u32 *rx_ant);
 
        int (*remain_on_channel)(struct ieee80211_hw *hw,
+                                struct ieee80211_vif *vif,
                                 struct ieee80211_channel *chan,
-                                enum nl80211_channel_type channel_type,
                                 int duration);
        int (*cancel_remain_on_channel)(struct ieee80211_hw *hw);
        int (*set_ringparam)(struct ieee80211_hw *hw, u32 tx, u32 rx);
@@ -2539,6 +2636,8 @@ struct ieee80211_ops {
        void (*unassign_vif_chanctx)(struct ieee80211_hw *hw,
                                     struct ieee80211_vif *vif,
                                     struct ieee80211_chanctx_conf *ctx);
+
+       void (*restart_complete)(struct ieee80211_hw *hw);
 };
 
 /**
@@ -3384,6 +3483,21 @@ void ieee80211_sched_scan_results(struct ieee80211_hw *hw);
  */
 void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);
 
+/**
+ * enum ieee80211_interface_iteration_flags - interface iteration flags
+ * @IEEE80211_IFACE_ITER_NORMAL: Iterate over all interfaces that have
+ *     been added to the driver; However, note that during hardware
+ *     reconfiguration (after restart_hw) it will iterate over a new
+ *     interface and over all the existing interfaces even if they
+ *     haven't been re-added to the driver yet.
+ * @IEEE80211_IFACE_ITER_RESUME_ALL: During resume, iterate over all
+ *     interfaces, even if they haven't been re-added to the driver yet.
+ */
+enum ieee80211_interface_iteration_flags {
+       IEEE80211_IFACE_ITER_NORMAL     = 0,
+       IEEE80211_IFACE_ITER_RESUME_ALL = BIT(0),
+};
+
 /**
  * ieee80211_iterate_active_interfaces - iterate active interfaces
  *
@@ -3392,13 +3506,15 @@ void ieee80211_sched_scan_stopped(struct ieee80211_hw *hw);
  * This function allows the iterator function to sleep, when the iterator
  * function is atomic @ieee80211_iterate_active_interfaces_atomic can
  * be used.
- * Does not iterate over a new interface during add_interface()
+ * Does not iterate over a new interface during add_interface().
  *
  * @hw: the hardware struct of which the interfaces should be iterated over
+ * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
  * @iterator: the iterator function to call
  * @data: first argument of the iterator function
  */
 void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
+                                        u32 iter_flags,
                                         void (*iterator)(void *data, u8 *mac,
                                                struct ieee80211_vif *vif),
                                         void *data);
@@ -3410,13 +3526,15 @@ void ieee80211_iterate_active_interfaces(struct ieee80211_hw *hw,
  * hardware that are currently active and calls the callback for them.
  * This function requires the iterator callback function to be atomic,
  * if that is not desired, use @ieee80211_iterate_active_interfaces instead.
- * Does not iterate over a new interface during add_interface()
+ * Does not iterate over a new interface during add_interface().
  *
  * @hw: the hardware struct of which the interfaces should be iterated over
+ * @iter_flags: iteration flags, see &enum ieee80211_interface_iteration_flags
  * @iterator: the iterator function to call, cannot sleep
  * @data: first argument of the iterator function
  */
 void ieee80211_iterate_active_interfaces_atomic(struct ieee80211_hw *hw,
+                                               u32 iter_flags,
                                                void (*iterator)(void *data,
                                                    u8 *mac,
                                                    struct ieee80211_vif *vif),
index 639f50af42dfa1481206642c986dec080f34f445..671953e11575449b30a10081d5b7aa7b26c0fa0a 100644 (file)
@@ -149,6 +149,8 @@ void *nfc_hci_get_clientdata(struct nfc_hci_dev *hdev);
 
 void nfc_hci_driver_failure(struct nfc_hci_dev *hdev, int err);
 
+int nfc_hci_result_to_errno(u8 result);
+
 /* Host IDs */
 #define NFC_HCI_HOST_CONTROLLER_ID     0x00
 #define NFC_HCI_TERMINAL_HOST_ID       0x01
@@ -235,5 +237,6 @@ int nfc_hci_send_response(struct nfc_hci_dev *hdev, u8 gate, u8 response,
 int nfc_hci_send_event(struct nfc_hci_dev *hdev, u8 gate, u8 event,
                       const u8 *param, size_t param_len);
 int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate);
+u32 nfc_hci_sak_to_protocol(u8 sak);
 
 #endif /* __NET_HCI_H */
index 617d0fbfc96f43ae51f372f6eec2b968e507e163..33a417481ad83583c33f53d834343d82d8e56433 100644 (file)
  *     to get a list of all present wiphys.
  * @NL80211_CMD_SET_WIPHY: set wiphy parameters, needs %NL80211_ATTR_WIPHY or
  *     %NL80211_ATTR_IFINDEX; can be used to set %NL80211_ATTR_WIPHY_NAME,
- *     %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ,
- *     %NL80211_ATTR_WIPHY_CHANNEL_TYPE, %NL80211_ATTR_WIPHY_RETRY_SHORT,
+ *     %NL80211_ATTR_WIPHY_TXQ_PARAMS, %NL80211_ATTR_WIPHY_FREQ (and the
+ *     attributes determining the channel width; this is used for setting
+ *     monitor mode channel),  %NL80211_ATTR_WIPHY_RETRY_SHORT,
  *     %NL80211_ATTR_WIPHY_RETRY_LONG, %NL80211_ATTR_WIPHY_FRAG_THRESHOLD,
  *     and/or %NL80211_ATTR_WIPHY_RTS_THRESHOLD.
  *     However, for setting the channel, see %NL80211_CMD_SET_CHANNEL
  *     %NL80211_ATTR_AKM_SUITES, %NL80211_ATTR_PRIVACY,
  *     %NL80211_ATTR_AUTH_TYPE and %NL80211_ATTR_INACTIVITY_TIMEOUT.
  *     The channel to use can be set on the interface or be given using the
- *     %NL80211_ATTR_WIPHY_FREQ and %NL80211_ATTR_WIPHY_CHANNEL_TYPE attrs.
+ *     %NL80211_ATTR_WIPHY_FREQ and the attributes determining channel width.
  * @NL80211_CMD_NEW_BEACON: old alias for %NL80211_CMD_START_AP
  * @NL80211_CMD_STOP_AP: Stop AP operation on the given interface
  * @NL80211_CMD_DEL_BEACON: old alias for %NL80211_CMD_STOP_AP
  *     a response while being associated to an AP on another channel.
  *     %NL80211_ATTR_IFINDEX is used to specify which interface (and thus
  *     radio) is used. %NL80211_ATTR_WIPHY_FREQ is used to specify the
- *     frequency for the operation and %NL80211_ATTR_WIPHY_CHANNEL_TYPE may be
- *     optionally used to specify additional channel parameters.
+ *     frequency for the operation.
  *     %NL80211_ATTR_DURATION is used to specify the duration in milliseconds
  *     to remain on the channel. This command is also used as an event to
  *     notify when the requested duration starts (it may take a while for the
  *     as an event indicating reception of a frame that was not processed in
  *     kernel code, but is for us (i.e., which may need to be processed in a
  *     user space application). %NL80211_ATTR_FRAME is used to specify the
- *     frame contents (including header). %NL80211_ATTR_WIPHY_FREQ (and
- *     optionally %NL80211_ATTR_WIPHY_CHANNEL_TYPE) is used to indicate on
- *     which channel the frame is to be transmitted or was received. If this
- *     channel is not the current channel (remain-on-channel or the
- *     operational channel) the device will switch to the given channel and
- *     transmit the frame, optionally waiting for a response for the time
+ *     frame contents (including header). %NL80211_ATTR_WIPHY_FREQ is used
+ *     to indicate on which channel the frame is to be transmitted or was
+ *     received. If this channel is not the current channel (remain-on-channel
+ *     or the operational channel) the device will switch to the given channel
+ *     and transmit the frame, optionally waiting for a response for the time
  *     specified using %NL80211_ATTR_DURATION. When called, this operation
  *     returns a cookie (%NL80211_ATTR_COOKIE) that will be included with the
  *     TX status event pertaining to the TX request.
  *     command is used as an event to indicate the that a trigger level was
  *     reached.
  * @NL80211_CMD_SET_CHANNEL: Set the channel (using %NL80211_ATTR_WIPHY_FREQ
- *     and %NL80211_ATTR_WIPHY_CHANNEL_TYPE) the given interface (identifed
- *     by %NL80211_ATTR_IFINDEX) shall operate on.
+ *     and the attributes determining channel width) the given interface
+ *     (identifed by %NL80211_ATTR_IFINDEX) shall operate on.
  *     In case multiple channels are supported by the device, the mechanism
  *     with which it switches channels is implementation-defined.
  *     When a monitor interface is given, it can only switch channel while
  *     of PMKSA caching dandidates.
  *
  * @NL80211_CMD_TDLS_OPER: Perform a high-level TDLS command (e.g. link setup).
+ *     In addition, this can be used as an event to request userspace to take
+ *     actions on TDLS links (set up a new link or tear down an existing one).
+ *     In such events, %NL80211_ATTR_TDLS_OPERATION indicates the requested
+ *     operation, %NL80211_ATTR_MAC contains the peer MAC address, and
+ *     %NL80211_ATTR_REASON_CODE the reason code to be used (only with
+ *     %NL80211_TDLS_TEARDOWN).
  * @NL80211_CMD_TDLS_MGMT: Send a TDLS management frame.
  *
  * @NL80211_CMD_UNEXPECTED_FRAME: Used by an application controlling an AP
  *
  * @NL80211_CMD_CH_SWITCH_NOTIFY: An AP or GO may decide to switch channels
  *     independently of the userspace SME, send this event indicating
- *     %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ with
- *     %NL80211_ATTR_WIPHY_CHANNEL_TYPE.
+ *     %NL80211_ATTR_IFINDEX is now on %NL80211_ATTR_WIPHY_FREQ and the
+ *     attributes determining channel width.
  *
  * @NL80211_CMD_START_P2P_DEVICE: Start the given P2P Device, identified by
  *     its %NL80211_ATTR_WDEV identifier. It must have been created with
  *     station, due to particular reason. %NL80211_ATTR_CONN_FAILED_REASON
  *     is used for this.
  *
+ * @NL80211_CMD_SET_MCAST_RATE: Change the rate used to send multicast frames
+ *     for IBSS or MESH vif.
+ *
  * @NL80211_CMD_MAX: highest used command number
  * @__NL80211_CMD_AFTER_LAST: internal use
  */
@@ -726,6 +734,8 @@ enum nl80211_commands {
 
        NL80211_CMD_CONN_FAILED,
 
+       NL80211_CMD_SET_MCAST_RATE,
+
        /* add new commands above here */
 
        /* used to define NL80211_CMD_MAX below */
@@ -762,14 +772,26 @@ enum nl80211_commands {
  *     /sys/class/ieee80211/<phyname>/index
  * @NL80211_ATTR_WIPHY_NAME: wiphy name (used for renaming)
  * @NL80211_ATTR_WIPHY_TXQ_PARAMS: a nested array of TX queue parameters
- * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz
+ * @NL80211_ATTR_WIPHY_FREQ: frequency of the selected channel in MHz,
+ *     defines the channel together with the (deprecated)
+ *     %NL80211_ATTR_WIPHY_CHANNEL_TYPE attribute or the attributes
+ *     %NL80211_ATTR_CHANNEL_WIDTH and if needed %NL80211_ATTR_CENTER_FREQ1
+ *     and %NL80211_ATTR_CENTER_FREQ2
+ * @NL80211_ATTR_CHANNEL_WIDTH: u32 attribute containing one of the values
+ *     of &enum nl80211_chan_width, describing the channel width. See the
+ *     documentation of the enum for more information.
+ * @NL80211_ATTR_CENTER_FREQ1: Center frequency of the first part of the
+ *     channel, used for anything but 20 MHz bandwidth
+ * @NL80211_ATTR_CENTER_FREQ2: Center frequency of the second part of the
+ *     channel, used only for 80+80 MHz bandwidth
  * @NL80211_ATTR_WIPHY_CHANNEL_TYPE: included with NL80211_ATTR_WIPHY_FREQ
- *     if HT20 or HT40 are allowed (i.e., 802.11n disabled if not included):
+ *     if HT20 or HT40 are to be used (i.e., HT disabled if not included):
  *     NL80211_CHAN_NO_HT = HT not allowed (i.e., same as not including
  *             this attribute)
  *     NL80211_CHAN_HT20 = HT20 only
  *     NL80211_CHAN_HT40MINUS = secondary channel is below the primary channel
  *     NL80211_CHAN_HT40PLUS = secondary channel is above the primary channel
+ *     This attribute is now deprecated.
  * @NL80211_ATTR_WIPHY_RETRY_SHORT: TX retry limit for frames whose length is
  *     less than or equal to the RTS threshold; allowed range: 1..255;
  *     dot11ShortRetryLimit; u8
@@ -1544,6 +1566,10 @@ enum nl80211_attrs {
 
        NL80211_ATTR_SCAN_FLAGS,
 
+       NL80211_ATTR_CHANNEL_WIDTH,
+       NL80211_ATTR_CENTER_FREQ1,
+       NL80211_ATTR_CENTER_FREQ2,
+
        /* add attributes here, update the policy in nl80211.c */
 
        __NL80211_ATTR_AFTER_LAST,
@@ -1708,10 +1734,15 @@ struct nl80211_sta_flag_update {
  * @__NL80211_RATE_INFO_INVALID: attribute number 0 is reserved
  * @NL80211_RATE_INFO_BITRATE: total bitrate (u16, 100kbit/s)
  * @NL80211_RATE_INFO_MCS: mcs index for 802.11n (u8)
- * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 Mhz dualchannel bitrate
+ * @NL80211_RATE_INFO_40_MHZ_WIDTH: 40 MHz dualchannel bitrate
  * @NL80211_RATE_INFO_SHORT_GI: 400ns guard interval
  * @NL80211_RATE_INFO_BITRATE32: total bitrate (u32, 100kbit/s)
  * @NL80211_RATE_INFO_MAX: highest rate_info number currently defined
+ * @NL80211_RATE_INFO_VHT_MCS: MCS index for VHT (u8)
+ * @NL80211_RATE_INFO_VHT_NSS: number of streams in VHT (u8)
+ * @NL80211_RATE_INFO_80_MHZ_WIDTH: 80 MHz VHT rate
+ * @NL80211_RATE_INFO_80P80_MHZ_WIDTH: 80+80 MHz VHT rate
+ * @NL80211_RATE_INFO_160_MHZ_WIDTH: 160 MHz VHT rate
  * @__NL80211_RATE_INFO_AFTER_LAST: internal use
  */
 enum nl80211_rate_info {
@@ -1721,6 +1752,11 @@ enum nl80211_rate_info {
        NL80211_RATE_INFO_40_MHZ_WIDTH,
        NL80211_RATE_INFO_SHORT_GI,
        NL80211_RATE_INFO_BITRATE32,
+       NL80211_RATE_INFO_VHT_MCS,
+       NL80211_RATE_INFO_VHT_NSS,
+       NL80211_RATE_INFO_80_MHZ_WIDTH,
+       NL80211_RATE_INFO_80P80_MHZ_WIDTH,
+       NL80211_RATE_INFO_160_MHZ_WIDTH,
 
        /* keep last */
        __NL80211_RATE_INFO_AFTER_LAST,
@@ -2429,6 +2465,15 @@ enum nl80211_ac {
 #define NL80211_TXQ_Q_BE       NL80211_AC_BE
 #define NL80211_TXQ_Q_BK       NL80211_AC_BK
 
+/**
+ * enum nl80211_channel_type - channel type
+ * @NL80211_CHAN_NO_HT: 20 MHz, non-HT channel
+ * @NL80211_CHAN_HT20: 20 MHz HT channel
+ * @NL80211_CHAN_HT40MINUS: HT40 channel, secondary channel
+ *     below the control channel
+ * @NL80211_CHAN_HT40PLUS: HT40 channel, secondary channel
+ *     above the control channel
+ */
 enum nl80211_channel_type {
        NL80211_CHAN_NO_HT,
        NL80211_CHAN_HT20,
@@ -2436,6 +2481,32 @@ enum nl80211_channel_type {
        NL80211_CHAN_HT40PLUS
 };
 
+/**
+ * enum nl80211_chan_width - channel width definitions
+ *
+ * These values are used with the %NL80211_ATTR_CHANNEL_WIDTH
+ * attribute.
+ *
+ * @NL80211_CHAN_WIDTH_20_NOHT: 20 MHz, non-HT channel
+ * @NL80211_CHAN_WIDTH_20: 20 MHz HT channel
+ * @NL80211_CHAN_WIDTH_40: 40 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ *     attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_80: 80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ *     attribute must be provided as well
+ * @NL80211_CHAN_WIDTH_80P80: 80+80 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ *     and %NL80211_ATTR_CENTER_FREQ2 attributes must be provided as well
+ * @NL80211_CHAN_WIDTH_160: 160 MHz channel, the %NL80211_ATTR_CENTER_FREQ1
+ *     attribute must be provided as well
+ */
+enum nl80211_chan_width {
+       NL80211_CHAN_WIDTH_20_NOHT,
+       NL80211_CHAN_WIDTH_20,
+       NL80211_CHAN_WIDTH_40,
+       NL80211_CHAN_WIDTH_80,
+       NL80211_CHAN_WIDTH_80P80,
+       NL80211_CHAN_WIDTH_160,
+};
+
 /**
  * enum nl80211_bss - netlink attributes for a BSS
  *
@@ -3051,6 +3122,10 @@ enum nl80211_ap_sme_features {
  * @NL80211_FEATURE_LOW_PRIORITY_SCAN: This driver supports low priority scan
  * @NL80211_FEATURE_SCAN_FLUSH: Scan flush is supported
  * @NL80211_FEATURE_AP_SCAN: Support scanning using an AP vif
+ * @NL80211_FEATURE_VIF_TXPOWER: The driver supports per-vif TX power setting
+ * @NL80211_FEATURE_NEED_OBSS_SCAN: The driver expects userspace to perform
+ *     OBSS scans and generate 20/40 BSS coex reports. This flag is used only
+ *     for drivers implementing the CONNECT API, for AUTH/ASSOC it is implied.
  */
 enum nl80211_feature_flags {
        NL80211_FEATURE_SK_TX_STATUS                    = 1 << 0,
@@ -3062,6 +3137,8 @@ enum nl80211_feature_flags {
        NL80211_FEATURE_LOW_PRIORITY_SCAN               = 1 << 6,
        NL80211_FEATURE_SCAN_FLUSH                      = 1 << 7,
        NL80211_FEATURE_AP_SCAN                         = 1 << 8,
+       NL80211_FEATURE_VIF_TXPOWER                     = 1 << 9,
+       NL80211_FEATURE_NEED_OBSS_SCAN                  = 1 << 10,
 };
 
 /**
index 1c11d0dcd863951c400cb55156b11b9446582fee..d3f3f7b1d32cd06b082142bcbce02c630cd4eb20 100644 (file)
@@ -48,4 +48,3 @@ source "net/bluetooth/cmtp/Kconfig"
 source "net/bluetooth/hidp/Kconfig"
 
 source "drivers/bluetooth/Kconfig"
-
index d5136cfb57e2e33276b93947d7b64aa3b4d98fa8..2f67d5ecc907e6dfc0ca74fcc21fbf12a527b175 100644 (file)
@@ -423,7 +423,7 @@ static int a2mp_getampassoc_rsp(struct amp_mgr *mgr, struct sk_buff *skb,
 
        BT_DBG("Created hcon %p: loc:%d -> rem:%d", hcon, hdev->id, rsp->id);
 
-       mgr->bredr_chan->ctrl_id = rsp->id;
+       mgr->bredr_chan->remote_amp_id = rsp->id;
 
        amp_create_phylink(hdev, mgr, hcon);
 
@@ -939,7 +939,7 @@ void a2mp_send_create_phy_link_req(struct hci_dev *hdev, u8 status)
                goto clean;
 
        req->local_id = hdev->id;
-       req->remote_id = bredr_chan->ctrl_id;
+       req->remote_id = bredr_chan->remote_amp_id;
        memcpy(req->amp_assoc, loc_assoc->data, loc_assoc->len);
 
        a2mp_send(mgr, A2MP_CREATEPHYSLINK_REQ, __next_ident(mgr), len, req);
index 231d7ef53ecb8a7461b44d3ca52b3eff4ee18739..1b0d92c0643a97595ea2ad44e69f2cf45b96a852 100644 (file)
@@ -372,3 +372,100 @@ void amp_accept_phylink(struct hci_dev *hdev, struct amp_mgr *mgr,
 
        hci_send_cmd(hdev, HCI_OP_ACCEPT_PHY_LINK, sizeof(cp), &cp);
 }
+
+void amp_physical_cfm(struct hci_conn *bredr_hcon, struct hci_conn *hs_hcon)
+{
+       struct hci_dev *bredr_hdev = hci_dev_hold(bredr_hcon->hdev);
+       struct amp_mgr *mgr = hs_hcon->amp_mgr;
+       struct l2cap_chan *bredr_chan;
+
+       BT_DBG("bredr_hcon %p hs_hcon %p mgr %p", bredr_hcon, hs_hcon, mgr);
+
+       if (!bredr_hdev || !mgr || !mgr->bredr_chan)
+               return;
+
+       bredr_chan = mgr->bredr_chan;
+
+       l2cap_chan_lock(bredr_chan);
+
+       set_bit(FLAG_EFS_ENABLE, &bredr_chan->flags);
+       bredr_chan->remote_amp_id = hs_hcon->remote_id;
+       bredr_chan->local_amp_id = hs_hcon->hdev->id;
+       bredr_chan->hs_hcon = hs_hcon;
+       bredr_chan->conn->mtu = hs_hcon->hdev->block_mtu;
+
+       __l2cap_physical_cfm(bredr_chan, 0);
+
+       l2cap_chan_unlock(bredr_chan);
+
+       hci_dev_put(bredr_hdev);
+}
+
+void amp_create_logical_link(struct l2cap_chan *chan)
+{
+       struct hci_cp_create_accept_logical_link cp;
+       struct hci_conn *hcon;
+       struct hci_dev *hdev;
+
+       BT_DBG("chan %p", chan);
+
+       if (!chan->hs_hcon)
+               return;
+
+       hdev = hci_dev_hold(chan->hs_hcon->hdev);
+       if (!hdev)
+               return;
+
+       BT_DBG("chan %p dst %pMR", chan, chan->conn->dst);
+
+       hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, chan->conn->dst);
+       if (!hcon)
+               goto done;
+
+       cp.phy_handle = hcon->handle;
+
+       cp.tx_flow_spec.id = chan->local_id;
+       cp.tx_flow_spec.stype = chan->local_stype;
+       cp.tx_flow_spec.msdu = cpu_to_le16(chan->local_msdu);
+       cp.tx_flow_spec.sdu_itime = cpu_to_le32(chan->local_sdu_itime);
+       cp.tx_flow_spec.acc_lat = cpu_to_le32(chan->local_acc_lat);
+       cp.tx_flow_spec.flush_to = cpu_to_le32(chan->local_flush_to);
+
+       cp.rx_flow_spec.id = chan->remote_id;
+       cp.rx_flow_spec.stype = chan->remote_stype;
+       cp.rx_flow_spec.msdu = cpu_to_le16(chan->remote_msdu);
+       cp.rx_flow_spec.sdu_itime = cpu_to_le32(chan->remote_sdu_itime);
+       cp.rx_flow_spec.acc_lat = cpu_to_le32(chan->remote_acc_lat);
+       cp.rx_flow_spec.flush_to = cpu_to_le32(chan->remote_flush_to);
+
+       if (hcon->out)
+               hci_send_cmd(hdev, HCI_OP_CREATE_LOGICAL_LINK, sizeof(cp),
+                            &cp);
+       else
+               hci_send_cmd(hdev, HCI_OP_ACCEPT_LOGICAL_LINK, sizeof(cp),
+                            &cp);
+
+done:
+       hci_dev_put(hdev);
+}
+
+void amp_disconnect_logical_link(struct hci_chan *hchan)
+{
+       struct hci_conn *hcon = hchan->conn;
+       struct hci_cp_disconn_logical_link cp;
+
+       if (hcon->state != BT_CONNECTED) {
+               BT_DBG("hchan %p not connected", hchan);
+               return;
+       }
+
+       cp.log_handle = cpu_to_le16(hchan->handle);
+       hci_send_cmd(hcon->hdev, HCI_OP_DISCONN_LOGICAL_LINK, sizeof(cp), &cp);
+}
+
+void amp_destroy_logical_link(struct hci_chan *hchan, u8 reason)
+{
+       BT_DBG("hchan %p", hchan);
+
+       hci_chan_del(hchan);
+}
index 98f86f91d47c691b9e6604b73e2e8248f29921cf..e58c8b32589c44811c042a623c48e1ca1d8550a1 100644 (file)
@@ -25,7 +25,6 @@
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/export.h>
 #include <linux/etherdevice.h>
 
 #include <net/bluetooth/bluetooth.h>
index 50f0d135eb8f201daf8156c433f08a973bfa338f..a4a9d4b6816c43b3216eee038f961301978b5713 100644 (file)
@@ -20,7 +20,7 @@
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
+#include <linux/export.h>
 #include <linux/proc_fs.h>
 #include <linux/seq_file.h>
 #include <linux/types.h>
index aacb802d1ee45d419aac1555442bb08edf227dc9..1c57482112b6e5c1eebfa30ce1ac84375db737dd 100644 (file)
@@ -20,7 +20,7 @@
    SOFTWARE IS DISCLAIMED.
 */
 
-#include <linux/module.h>
+#include <linux/export.h>
 
 #include <linux/types.h>
 #include <linux/capability.h>
index fe646211c61f5f0a056884e34bdff6c0336f9043..25bfce0666ebff70258019ddb1bba9b6f1eca967 100644 (file)
@@ -502,6 +502,9 @@ static struct hci_conn *hci_connect_le(struct hci_dev *hdev, bdaddr_t *dst,
 {
        struct hci_conn *le;
 
+       if (test_bit(HCI_LE_PERIPHERAL, &hdev->flags))
+               return ERR_PTR(-ENOTSUPP);
+
        le = hci_conn_hash_lookup_ba(hdev, LE_LINK, dst);
        if (!le) {
                le = hci_conn_hash_lookup_state(hdev, LE_LINK, BT_CONNECT);
@@ -959,6 +962,7 @@ struct hci_chan *hci_chan_create(struct hci_conn *conn)
 
        chan->conn = conn;
        skb_queue_head_init(&chan->data_q);
+       chan->state = BT_CONNECTED;
 
        list_add_rcu(&chan->list, &conn->chan_list);
 
@@ -976,6 +980,8 @@ void hci_chan_del(struct hci_chan *chan)
 
        synchronize_rcu();
 
+       hci_conn_put(conn);
+
        skb_queue_purge(&chan->data_q);
        kfree(chan);
 }
index f01e5e135b998ee853c2bbddfec528ebcfc6f84b..7140f83328a2a3b7ff00a5aa4fcdf72b87fcd5d9 100644 (file)
@@ -178,48 +178,13 @@ static void hci_reset_req(struct hci_dev *hdev, unsigned long opt)
 
 static void bredr_init(struct hci_dev *hdev)
 {
-       struct hci_cp_delete_stored_link_key cp;
-       __le16 param;
-       __u8 flt_type;
-
        hdev->flow_ctl_mode = HCI_FLOW_CTL_MODE_PACKET_BASED;
 
-       /* Mandatory initialization */
-
        /* Read Local Supported Features */
        hci_send_cmd(hdev, HCI_OP_READ_LOCAL_FEATURES, 0, NULL);
 
        /* Read Local Version */
        hci_send_cmd(hdev, HCI_OP_READ_LOCAL_VERSION, 0, NULL);
-
-       /* Read Buffer Size (ACL mtu, max pkt, etc.) */
-       hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
-
-       /* Read BD Address */
-       hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
-
-       /* Read Class of Device */
-       hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
-
-       /* Read Local Name */
-       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
-
-       /* Read Voice Setting */
-       hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
-
-       /* Optional initialization */
-
-       /* Clear Event Filters */
-       flt_type = HCI_FLT_CLEAR_ALL;
-       hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
-
-       /* Connection accept timeout ~20 secs */
-       param = __constant_cpu_to_le16(0x7d00);
-       hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
-
-       bacpy(&cp.bdaddr, BDADDR_ANY);
-       cp.delete_all = 1;
-       hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
 }
 
 static void amp_init(struct hci_dev *hdev)
@@ -273,14 +238,6 @@ static void hci_init_req(struct hci_dev *hdev, unsigned long opt)
        }
 }
 
-static void hci_le_init_req(struct hci_dev *hdev, unsigned long opt)
-{
-       BT_DBG("%s", hdev->name);
-
-       /* Read LE buffer size */
-       hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
-}
-
 static void hci_scan_req(struct hci_dev *hdev, unsigned long opt)
 {
        __u8 scan = opt;
@@ -477,6 +434,8 @@ bool hci_inquiry_cache_update(struct hci_dev *hdev, struct inquiry_data *data,
 
        BT_DBG("cache %p, %pMR", cache, &data->bdaddr);
 
+       hci_remove_remote_oob_data(hdev, &data->bdaddr);
+
        if (ssp)
                *ssp = data->ssp_mode;
 
@@ -637,6 +596,99 @@ done:
        return err;
 }
 
+static u8 create_ad(struct hci_dev *hdev, u8 *ptr)
+{
+       u8 ad_len = 0, flags = 0;
+       size_t name_len;
+
+       if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
+               flags |= LE_AD_GENERAL;
+
+       if (!lmp_bredr_capable(hdev))
+               flags |= LE_AD_NO_BREDR;
+
+       if (lmp_le_br_capable(hdev))
+               flags |= LE_AD_SIM_LE_BREDR_CTRL;
+
+       if (lmp_host_le_br_capable(hdev))
+               flags |= LE_AD_SIM_LE_BREDR_HOST;
+
+       if (flags) {
+               BT_DBG("adv flags 0x%02x", flags);
+
+               ptr[0] = 2;
+               ptr[1] = EIR_FLAGS;
+               ptr[2] = flags;
+
+               ad_len += 3;
+               ptr += 3;
+       }
+
+       if (hdev->adv_tx_power != HCI_TX_POWER_INVALID) {
+               ptr[0] = 2;
+               ptr[1] = EIR_TX_POWER;
+               ptr[2] = (u8) hdev->adv_tx_power;
+
+               ad_len += 3;
+               ptr += 3;
+       }
+
+       name_len = strlen(hdev->dev_name);
+       if (name_len > 0) {
+               size_t max_len = HCI_MAX_AD_LENGTH - ad_len - 2;
+
+               if (name_len > max_len) {
+                       name_len = max_len;
+                       ptr[1] = EIR_NAME_SHORT;
+               } else
+                       ptr[1] = EIR_NAME_COMPLETE;
+
+               ptr[0] = name_len + 1;
+
+               memcpy(ptr + 2, hdev->dev_name, name_len);
+
+               ad_len += (name_len + 2);
+               ptr += (name_len + 2);
+       }
+
+       return ad_len;
+}
+
+int hci_update_ad(struct hci_dev *hdev)
+{
+       struct hci_cp_le_set_adv_data cp;
+       u8 len;
+       int err;
+
+       hci_dev_lock(hdev);
+
+       if (!lmp_le_capable(hdev)) {
+               err = -EINVAL;
+               goto unlock;
+       }
+
+       memset(&cp, 0, sizeof(cp));
+
+       len = create_ad(hdev, cp.data);
+
+       if (hdev->adv_data_len == len &&
+           memcmp(cp.data, hdev->adv_data, len) == 0) {
+               err = 0;
+               goto unlock;
+       }
+
+       memcpy(hdev->adv_data, cp.data, sizeof(cp.data));
+       hdev->adv_data_len = len;
+
+       cp.length = len;
+       err = hci_send_cmd(hdev, HCI_OP_LE_SET_ADV_DATA, sizeof(cp), &cp);
+
+unlock:
+       hci_dev_unlock(hdev);
+
+       return err;
+}
+
 /* ---- HCI ioctl helpers ---- */
 
 int hci_dev_open(__u16 dev)
@@ -687,10 +739,6 @@ int hci_dev_open(__u16 dev)
 
                ret = __hci_request(hdev, hci_init_req, 0, HCI_INIT_TIMEOUT);
 
-               if (lmp_host_le_capable(hdev))
-                       ret = __hci_request(hdev, hci_le_init_req, 0,
-                                           HCI_INIT_TIMEOUT);
-
                clear_bit(HCI_INIT, &hdev->flags);
        }
 
@@ -698,6 +746,7 @@ int hci_dev_open(__u16 dev)
                hci_dev_hold(hdev);
                set_bit(HCI_UP, &hdev->flags);
                hci_notify(hdev, HCI_DEV_UP);
+               hci_update_ad(hdev);
                if (!test_bit(HCI_SETUP, &hdev->dev_flags) &&
                    mgmt_valid_hdev(hdev)) {
                        hci_dev_lock(hdev);
@@ -1039,10 +1088,17 @@ int hci_get_dev_info(void __user *arg)
        di.type     = (hdev->bus & 0x0f) | (hdev->dev_type << 4);
        di.flags    = hdev->flags;
        di.pkt_type = hdev->pkt_type;
-       di.acl_mtu  = hdev->acl_mtu;
-       di.acl_pkts = hdev->acl_pkts;
-       di.sco_mtu  = hdev->sco_mtu;
-       di.sco_pkts = hdev->sco_pkts;
+       if (lmp_bredr_capable(hdev)) {
+               di.acl_mtu  = hdev->acl_mtu;
+               di.acl_pkts = hdev->acl_pkts;
+               di.sco_mtu  = hdev->sco_mtu;
+               di.sco_pkts = hdev->sco_pkts;
+       } else {
+               di.acl_mtu  = hdev->le_mtu;
+               di.acl_pkts = hdev->le_pkts;
+               di.sco_mtu  = 0;
+               di.sco_pkts = 0;
+       }
        di.link_policy = hdev->link_policy;
        di.link_mode   = hdev->link_mode;
 
@@ -1617,6 +1673,9 @@ int hci_le_scan(struct hci_dev *hdev, u8 type, u16 interval, u16 window,
 
        BT_DBG("%s", hdev->name);
 
+       if (test_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags))
+               return -ENOTSUPP;
+
        if (work_busy(&hdev->le_scan))
                return -EINPROGRESS;
 
@@ -1643,6 +1702,8 @@ struct hci_dev *hci_alloc_dev(void)
        hdev->esco_type = (ESCO_HV1);
        hdev->link_mode = (HCI_LM_ACCEPT);
        hdev->io_capability = 0x03; /* No Input No Output */
+       hdev->inq_tx_power = HCI_TX_POWER_INVALID;
+       hdev->adv_tx_power = HCI_TX_POWER_INVALID;
 
        hdev->sniff_max_interval = 800;
        hdev->sniff_min_interval = 80;
index 0383635f91fbc18991abe090c6a637d5d12d96e7..9f5c5f244502ef3cad289c8477fb05ad3990f37e 100644 (file)
@@ -24,7 +24,6 @@
 
 /* Bluetooth HCI event handling. */
 
-#include <linux/export.h>
 #include <asm/unaligned.h>
 
 #include <net/bluetooth/bluetooth.h>
@@ -203,6 +202,11 @@ static void hci_cc_reset(struct hci_dev *hdev, struct sk_buff *skb)
                             BIT(HCI_PERIODIC_INQ));
 
        hdev->discovery.state = DISCOVERY_STOPPED;
+       hdev->inq_tx_power = HCI_TX_POWER_INVALID;
+       hdev->adv_tx_power = HCI_TX_POWER_INVALID;
+
+       memset(hdev->adv_data, 0, sizeof(hdev->adv_data));
+       hdev->adv_data_len = 0;
 }
 
 static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
@@ -225,6 +229,9 @@ static void hci_cc_write_local_name(struct hci_dev *hdev, struct sk_buff *skb)
 
        hci_dev_unlock(hdev);
 
+       if (!status && !test_bit(HCI_INIT, &hdev->flags))
+               hci_update_ad(hdev);
+
        hci_req_complete(hdev, HCI_OP_WRITE_LOCAL_NAME, status);
 }
 
@@ -440,7 +447,7 @@ static void hci_cc_host_buffer_size(struct hci_dev *hdev, struct sk_buff *skb)
 static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
-       void *sent;
+       struct hci_cp_write_ssp_mode *sent;
 
        BT_DBG("%s status 0x%2.2x", hdev->name, status);
 
@@ -448,10 +455,17 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
        if (!sent)
                return;
 
+       if (!status) {
+               if (sent->mode)
+                       hdev->host_features[0] |= LMP_HOST_SSP;
+               else
+                       hdev->host_features[0] &= ~LMP_HOST_SSP;
+       }
+
        if (test_bit(HCI_MGMT, &hdev->dev_flags))
-               mgmt_ssp_enable_complete(hdev, *((u8 *) sent), status);
+               mgmt_ssp_enable_complete(hdev, sent->mode, status);
        else if (!status) {
-               if (*((u8 *) sent))
+               if (sent->mode)
                        set_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
                else
                        clear_bit(HCI_SSP_ENABLED, &hdev->dev_flags);
@@ -460,10 +474,10 @@ static void hci_cc_write_ssp_mode(struct hci_dev *hdev, struct sk_buff *skb)
 
 static u8 hci_get_inquiry_mode(struct hci_dev *hdev)
 {
-       if (hdev->features[6] & LMP_EXT_INQ)
+       if (lmp_ext_inq_capable(hdev))
                return 2;
 
-       if (hdev->features[3] & LMP_RSSI_INQ)
+       if (lmp_inq_rssi_capable(hdev))
                return 1;
 
        if (hdev->manufacturer == 11 && hdev->hci_rev == 0x00 &&
@@ -507,28 +521,30 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
        if (hdev->hci_ver < BLUETOOTH_VER_1_2)
                return;
 
-       events[4] |= 0x01; /* Flow Specification Complete */
-       events[4] |= 0x02; /* Inquiry Result with RSSI */
-       events[4] |= 0x04; /* Read Remote Extended Features Complete */
-       events[5] |= 0x08; /* Synchronous Connection Complete */
-       events[5] |= 0x10; /* Synchronous Connection Changed */
+       if (lmp_bredr_capable(hdev)) {
+               events[4] |= 0x01; /* Flow Specification Complete */
+               events[4] |= 0x02; /* Inquiry Result with RSSI */
+               events[4] |= 0x04; /* Read Remote Extended Features Complete */
+               events[5] |= 0x08; /* Synchronous Connection Complete */
+               events[5] |= 0x10; /* Synchronous Connection Changed */
+       }
 
-       if (hdev->features[3] & LMP_RSSI_INQ)
+       if (lmp_inq_rssi_capable(hdev))
                events[4] |= 0x02; /* Inquiry Result with RSSI */
 
        if (lmp_sniffsubr_capable(hdev))
                events[5] |= 0x20; /* Sniff Subrating */
 
-       if (hdev->features[5] & LMP_PAUSE_ENC)
+       if (lmp_pause_enc_capable(hdev))
                events[5] |= 0x80; /* Encryption Key Refresh Complete */
 
-       if (hdev->features[6] & LMP_EXT_INQ)
+       if (lmp_ext_inq_capable(hdev))
                events[5] |= 0x40; /* Extended Inquiry Result */
 
        if (lmp_no_flush_capable(hdev))
                events[7] |= 0x01; /* Enhanced Flush Complete */
 
-       if (hdev->features[7] & LMP_LSTO)
+       if (lmp_lsto_capable(hdev))
                events[6] |= 0x80; /* Link Supervision Timeout Changed */
 
        if (lmp_ssp_capable(hdev)) {
@@ -548,6 +564,53 @@ static void hci_setup_event_mask(struct hci_dev *hdev)
                events[7] |= 0x20;      /* LE Meta-Event */
 
        hci_send_cmd(hdev, HCI_OP_SET_EVENT_MASK, sizeof(events), events);
+
+       if (lmp_le_capable(hdev)) {
+               memset(events, 0, sizeof(events));
+               events[0] = 0x1f;
+               hci_send_cmd(hdev, HCI_OP_LE_SET_EVENT_MASK,
+                            sizeof(events), events);
+       }
+}
+
+static void bredr_setup(struct hci_dev *hdev)
+{
+       struct hci_cp_delete_stored_link_key cp;
+       __le16 param;
+       __u8 flt_type;
+
+       /* Read Buffer Size (ACL mtu, max pkt, etc.) */
+       hci_send_cmd(hdev, HCI_OP_READ_BUFFER_SIZE, 0, NULL);
+
+       /* Read Class of Device */
+       hci_send_cmd(hdev, HCI_OP_READ_CLASS_OF_DEV, 0, NULL);
+
+       /* Read Local Name */
+       hci_send_cmd(hdev, HCI_OP_READ_LOCAL_NAME, 0, NULL);
+
+       /* Read Voice Setting */
+       hci_send_cmd(hdev, HCI_OP_READ_VOICE_SETTING, 0, NULL);
+
+       /* Clear Event Filters */
+       flt_type = HCI_FLT_CLEAR_ALL;
+       hci_send_cmd(hdev, HCI_OP_SET_EVENT_FLT, 1, &flt_type);
+
+       /* Connection accept timeout ~20 secs */
+       param = __constant_cpu_to_le16(0x7d00);
+       hci_send_cmd(hdev, HCI_OP_WRITE_CA_TIMEOUT, 2, &param);
+
+       bacpy(&cp.bdaddr, BDADDR_ANY);
+       cp.delete_all = 1;
+       hci_send_cmd(hdev, HCI_OP_DELETE_STORED_LINK_KEY, sizeof(cp), &cp);
+}
+
+static void le_setup(struct hci_dev *hdev)
+{
+       /* Read LE Buffer Size */
+       hci_send_cmd(hdev, HCI_OP_LE_READ_BUFFER_SIZE, 0, NULL);
+
+       /* Read LE Advertising Channel TX Power */
+       hci_send_cmd(hdev, HCI_OP_LE_READ_ADV_TX_POWER, 0, NULL);
 }
 
 static void hci_setup(struct hci_dev *hdev)
@@ -555,6 +618,15 @@ static void hci_setup(struct hci_dev *hdev)
        if (hdev->dev_type != HCI_BREDR)
                return;
 
+       /* Read BD Address */
+       hci_send_cmd(hdev, HCI_OP_READ_BD_ADDR, 0, NULL);
+
+       if (lmp_bredr_capable(hdev))
+               bredr_setup(hdev);
+
+       if (lmp_le_capable(hdev))
+               le_setup(hdev);
+
        hci_setup_event_mask(hdev);
 
        if (hdev->hci_ver > BLUETOOTH_VER_1_1)
@@ -575,13 +647,13 @@ static void hci_setup(struct hci_dev *hdev)
                }
        }
 
-       if (hdev->features[3] & LMP_RSSI_INQ)
+       if (lmp_inq_rssi_capable(hdev))
                hci_setup_inquiry_mode(hdev);
 
-       if (hdev->features[7] & LMP_INQ_TX_PWR)
+       if (lmp_inq_tx_pwr_capable(hdev))
                hci_send_cmd(hdev, HCI_OP_READ_INQ_RSP_TX_POWER, 0, NULL);
 
-       if (hdev->features[7] & LMP_EXTFEATURES) {
+       if (lmp_ext_feat_capable(hdev)) {
                struct hci_cp_read_local_ext_features cp;
 
                cp.page = 0x01;
@@ -628,11 +700,11 @@ static void hci_setup_link_policy(struct hci_dev *hdev)
 
        if (lmp_rswitch_capable(hdev))
                link_policy |= HCI_LP_RSWITCH;
-       if (hdev->features[0] & LMP_HOLD)
+       if (lmp_hold_capable(hdev))
                link_policy |= HCI_LP_HOLD;
        if (lmp_sniff_capable(hdev))
                link_policy |= HCI_LP_SNIFF;
-       if (hdev->features[1] & LMP_PARK)
+       if (lmp_park_capable(hdev))
                link_policy |= HCI_LP_PARK;
 
        cp.policy = cpu_to_le16(link_policy);
@@ -722,10 +794,10 @@ static void hci_set_le_support(struct hci_dev *hdev)
 
        if (test_bit(HCI_LE_ENABLED, &hdev->dev_flags)) {
                cp.le = 1;
-               cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
+               cp.simul = !!lmp_le_br_capable(hdev);
        }
 
-       if (cp.le != !!(hdev->host_features[0] & LMP_HOST_LE))
+       if (cp.le != !!lmp_host_le_capable(hdev))
                hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(cp),
                             &cp);
 }
@@ -1018,6 +1090,31 @@ static void hci_cc_le_read_buffer_size(struct hci_dev *hdev,
        hci_req_complete(hdev, HCI_OP_LE_READ_BUFFER_SIZE, rp->status);
 }
 
+static void hci_cc_le_read_adv_tx_power(struct hci_dev *hdev,
+                                       struct sk_buff *skb)
+{
+       struct hci_rp_le_read_adv_tx_power *rp = (void *) skb->data;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, rp->status);
+
+       if (!rp->status) {
+               hdev->adv_tx_power = rp->tx_power;
+               if (!test_bit(HCI_INIT, &hdev->flags))
+                       hci_update_ad(hdev);
+       }
+
+       hci_req_complete(hdev, HCI_OP_LE_READ_ADV_TX_POWER, rp->status);
+}
+
+static void hci_cc_le_set_event_mask(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       hci_req_complete(hdev, HCI_OP_LE_SET_EVENT_MASK, status);
+}
+
 static void hci_cc_user_confirm_reply(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_rp_user_confirm_reply *rp = (void *) skb->data;
@@ -1093,6 +1190,33 @@ static void hci_cc_read_local_oob_data_reply(struct hci_dev *hdev,
        hci_dev_unlock(hdev);
 }
 
+static void hci_cc_le_set_adv_enable(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       __u8 *sent, status = *((__u8 *) skb->data);
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+
+       sent = hci_sent_cmd_data(hdev, HCI_OP_LE_SET_ADV_ENABLE);
+       if (!sent)
+               return;
+
+       hci_dev_lock(hdev);
+
+       if (!status) {
+               if (*sent)
+                       set_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
+               else
+                       clear_bit(HCI_LE_PERIPHERAL, &hdev->dev_flags);
+       }
+
+       hci_dev_unlock(hdev);
+
+       if (!test_bit(HCI_INIT, &hdev->flags))
+               hci_update_ad(hdev);
+
+       hci_req_complete(hdev, HCI_OP_LE_SET_ADV_ENABLE, status);
+}
+
 static void hci_cc_le_set_scan_param(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -1207,6 +1331,11 @@ static void hci_cc_write_le_host_supported(struct hci_dev *hdev,
                        hdev->host_features[0] |= LMP_HOST_LE;
                else
                        hdev->host_features[0] &= ~LMP_HOST_LE;
+
+               if (sent->simul)
+                       hdev->host_features[0] |= LMP_HOST_LE_BREDR;
+               else
+                       hdev->host_features[0] &= ~LMP_HOST_LE_BREDR;
        }
 
        if (test_bit(HCI_MGMT, &hdev->dev_flags) &&
@@ -1718,14 +1847,23 @@ static void hci_cs_create_phylink(struct hci_dev *hdev, u8 status)
 
        BT_DBG("%s status 0x%2.2x", hdev->name, status);
 
-       if (status)
-               return;
-
        cp = hci_sent_cmd_data(hdev, HCI_OP_CREATE_PHY_LINK);
        if (!cp)
                return;
 
-       amp_write_remote_assoc(hdev, cp->phy_handle);
+       hci_dev_lock(hdev);
+
+       if (status) {
+               struct hci_conn *hcon;
+
+               hcon = hci_conn_hash_lookup_handle(hdev, cp->phy_handle);
+               if (hcon)
+                       hci_conn_del(hcon);
+       } else {
+               amp_write_remote_assoc(hdev, cp->phy_handle);
+       }
+
+       hci_dev_unlock(hdev);
 }
 
 static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
@@ -1744,6 +1882,11 @@ static void hci_cs_accept_phylink(struct hci_dev *hdev, u8 status)
        amp_write_remote_assoc(hdev, cp->phy_handle);
 }
 
+static void hci_cs_create_logical_link(struct hci_dev *hdev, u8 status)
+{
+       BT_DBG("%s status 0x%2.2x", hdev->name, status);
+}
+
 static void hci_inquiry_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        __u8 status = *((__u8 *) skb->data);
@@ -2441,6 +2584,14 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_le_read_buffer_size(hdev, skb);
                break;
 
+       case HCI_OP_LE_READ_ADV_TX_POWER:
+               hci_cc_le_read_adv_tx_power(hdev, skb);
+               break;
+
+       case HCI_OP_LE_SET_EVENT_MASK:
+               hci_cc_le_set_event_mask(hdev, skb);
+               break;
+
        case HCI_OP_USER_CONFIRM_REPLY:
                hci_cc_user_confirm_reply(hdev, skb);
                break;
@@ -2461,6 +2612,10 @@ static void hci_cmd_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cc_le_set_scan_param(hdev, skb);
                break;
 
+       case HCI_OP_LE_SET_ADV_ENABLE:
+               hci_cc_le_set_adv_enable(hdev, skb);
+               break;
+
        case HCI_OP_LE_SET_SCAN_ENABLE:
                hci_cc_le_set_scan_enable(hdev, skb);
                break;
@@ -2570,6 +2725,10 @@ static void hci_cmd_status_evt(struct hci_dev *hdev, struct sk_buff *skb)
                hci_cs_accept_phylink(hdev, ev->status);
                break;
 
+       case HCI_OP_CREATE_LOGICAL_LINK:
+               hci_cs_create_logical_link(hdev, ev->status);
+               break;
+
        default:
                BT_DBG("%s opcode 0x%4.4x", hdev->name, opcode);
                break;
@@ -3544,6 +3703,130 @@ unlock:
        hci_dev_unlock(hdev);
 }
 
+static void hci_phy_link_complete_evt(struct hci_dev *hdev,
+                                     struct sk_buff *skb)
+{
+       struct hci_ev_phy_link_complete *ev = (void *) skb->data;
+       struct hci_conn *hcon, *bredr_hcon;
+
+       BT_DBG("%s handle 0x%2.2x status 0x%2.2x", hdev->name, ev->phy_handle,
+              ev->status);
+
+       hci_dev_lock(hdev);
+
+       hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+       if (!hcon) {
+               hci_dev_unlock(hdev);
+               return;
+       }
+
+       if (ev->status) {
+               hci_conn_del(hcon);
+               hci_dev_unlock(hdev);
+               return;
+       }
+
+       bredr_hcon = hcon->amp_mgr->l2cap_conn->hcon;
+
+       hcon->state = BT_CONNECTED;
+       bacpy(&hcon->dst, &bredr_hcon->dst);
+
+       hci_conn_hold(hcon);
+       hcon->disc_timeout = HCI_DISCONN_TIMEOUT;
+       hci_conn_put(hcon);
+
+       hci_conn_hold_device(hcon);
+       hci_conn_add_sysfs(hcon);
+
+       amp_physical_cfm(bredr_hcon, hcon);
+
+       hci_dev_unlock(hdev);
+}
+
+static void hci_loglink_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
+{
+       struct hci_ev_logical_link_complete *ev = (void *) skb->data;
+       struct hci_conn *hcon;
+       struct hci_chan *hchan;
+       struct amp_mgr *mgr;
+
+       BT_DBG("%s log_handle 0x%4.4x phy_handle 0x%2.2x status 0x%2.2x",
+              hdev->name, le16_to_cpu(ev->handle), ev->phy_handle,
+              ev->status);
+
+       hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+       if (!hcon)
+               return;
+
+       /* Create AMP hchan */
+       hchan = hci_chan_create(hcon);
+       if (!hchan)
+               return;
+
+       hchan->handle = le16_to_cpu(ev->handle);
+
+       BT_DBG("hcon %p mgr %p hchan %p", hcon, hcon->amp_mgr, hchan);
+
+       mgr = hcon->amp_mgr;
+       if (mgr && mgr->bredr_chan) {
+               struct l2cap_chan *bredr_chan = mgr->bredr_chan;
+
+               l2cap_chan_lock(bredr_chan);
+
+               bredr_chan->conn->mtu = hdev->block_mtu;
+               l2cap_logical_cfm(bredr_chan, hchan, 0);
+               hci_conn_hold(hcon);
+
+               l2cap_chan_unlock(bredr_chan);
+       }
+}
+
+static void hci_disconn_loglink_complete_evt(struct hci_dev *hdev,
+                                            struct sk_buff *skb)
+{
+       struct hci_ev_disconn_logical_link_complete *ev = (void *) skb->data;
+       struct hci_chan *hchan;
+
+       BT_DBG("%s log handle 0x%4.4x status 0x%2.2x", hdev->name,
+              le16_to_cpu(ev->handle), ev->status);
+
+       if (ev->status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       hchan = hci_chan_lookup_handle(hdev, le16_to_cpu(ev->handle));
+       if (!hchan)
+               goto unlock;
+
+       amp_destroy_logical_link(hchan, ev->reason);
+
+unlock:
+       hci_dev_unlock(hdev);
+}
+
+static void hci_disconn_phylink_complete_evt(struct hci_dev *hdev,
+                                            struct sk_buff *skb)
+{
+       struct hci_ev_disconn_phy_link_complete *ev = (void *) skb->data;
+       struct hci_conn *hcon;
+
+       BT_DBG("%s status 0x%2.2x", hdev->name, ev->status);
+
+       if (ev->status)
+               return;
+
+       hci_dev_lock(hdev);
+
+       hcon = hci_conn_hash_lookup_handle(hdev, ev->phy_handle);
+       if (hcon) {
+               hcon->state = BT_CLOSED;
+               hci_conn_del(hcon);
+       }
+
+       hci_dev_unlock(hdev);
+}
+
 static void hci_le_conn_complete_evt(struct hci_dev *hdev, struct sk_buff *skb)
 {
        struct hci_ev_le_conn_complete *ev = (void *) skb->data;
@@ -3871,6 +4154,22 @@ void hci_event_packet(struct hci_dev *hdev, struct sk_buff *skb)
                hci_remote_oob_data_request_evt(hdev, skb);
                break;
 
+       case HCI_EV_PHY_LINK_COMPLETE:
+               hci_phy_link_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_LOGICAL_LINK_COMPLETE:
+               hci_loglink_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_DISCONN_LOGICAL_LINK_COMPLETE:
+               hci_disconn_loglink_complete_evt(hdev, skb);
+               break;
+
+       case HCI_EV_DISCONN_PHY_LINK_COMPLETE:
+               hci_disconn_phylink_complete_evt(hdev, skb);
+               break;
+
        case HCI_EV_NUM_COMP_BLOCKS:
                hci_num_comp_blocks_evt(hdev, skb);
                break;
index 08efc256c9313382bbc666335ea645670eab087e..b52f66d22437ed58956c1c5227176498c70986f0 100644 (file)
@@ -38,6 +38,7 @@
 #include <net/bluetooth/l2cap.h>
 #include <net/bluetooth/smp.h>
 #include <net/bluetooth/a2mp.h>
+#include <net/bluetooth/amp.h>
 
 bool disable_ertm;
 
@@ -100,6 +101,23 @@ static struct l2cap_chan *l2cap_get_chan_by_scid(struct l2cap_conn *conn,
        return c;
 }
 
+/* Find channel with given DCID.
+ * Returns locked channel.
+ */
+static struct l2cap_chan *l2cap_get_chan_by_dcid(struct l2cap_conn *conn,
+                                                u16 cid)
+{
+       struct l2cap_chan *c;
+
+       mutex_lock(&conn->chan_lock);
+       c = __l2cap_get_chan_by_dcid(conn, cid);
+       if (c)
+               l2cap_chan_lock(c);
+       mutex_unlock(&conn->chan_lock);
+
+       return c;
+}
+
 static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,
                                                    u8 ident)
 {
@@ -112,6 +130,20 @@ static struct l2cap_chan *__l2cap_get_chan_by_ident(struct l2cap_conn *conn,
        return NULL;
 }
 
+static struct l2cap_chan *l2cap_get_chan_by_ident(struct l2cap_conn *conn,
+                                                 u8 ident)
+{
+       struct l2cap_chan *c;
+
+       mutex_lock(&conn->chan_lock);
+       c = __l2cap_get_chan_by_ident(conn, ident);
+       if (c)
+               l2cap_chan_lock(c);
+       mutex_unlock(&conn->chan_lock);
+
+       return c;
+}
+
 static struct l2cap_chan *__l2cap_global_chan_by_addr(__le16 psm, bdaddr_t *src)
 {
        struct l2cap_chan *c;
@@ -546,6 +578,13 @@ void l2cap_chan_del(struct l2cap_chan *chan, int err)
                        mgr->bredr_chan = NULL;
        }
 
+       if (chan->hs_hchan) {
+               struct hci_chan *hs_hchan = chan->hs_hchan;
+
+               BT_DBG("chan %p disconnect hs_hchan %p", chan, hs_hchan);
+               amp_disconnect_logical_link(hs_hchan);
+       }
+
        chan->ops->teardown(chan, err);
 
        if (test_bit(CONF_NOT_COMPLETE, &chan->conf_state))
@@ -718,6 +757,12 @@ static void l2cap_send_cmd(struct l2cap_conn *conn, u8 ident, u8 code, u16 len,
        hci_send_acl(conn->hchan, skb, flags);
 }
 
+static bool __chan_is_moving(struct l2cap_chan *chan)
+{
+       return chan->move_state != L2CAP_MOVE_STABLE &&
+              chan->move_state != L2CAP_MOVE_WAIT_PREPARE;
+}
+
 static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
 {
        struct hci_conn *hcon = chan->conn->hcon;
@@ -726,6 +771,15 @@ static void l2cap_do_send(struct l2cap_chan *chan, struct sk_buff *skb)
        BT_DBG("chan %p, skb %p len %d priority %u", chan, skb, skb->len,
               skb->priority);
 
+       if (chan->hs_hcon && !__chan_is_moving(chan)) {
+               if (chan->hs_hchan)
+                       hci_send_acl(chan->hs_hchan, skb, ACL_COMPLETE);
+               else
+                       kfree_skb(skb);
+
+               return;
+       }
+
        if (!test_bit(FLAG_FLUSHABLE, &chan->flags) &&
            lmp_no_flush_capable(hcon->hdev))
                flags = ACL_START_NO_FLUSH;
@@ -901,6 +955,9 @@ static void l2cap_send_sframe(struct l2cap_chan *chan,
        if (!control->sframe)
                return;
 
+       if (__chan_is_moving(chan))
+               return;
+
        if (test_and_clear_bit(CONN_SEND_FBIT, &chan->conn_state) &&
            !control->poll)
                control->final = 1;
@@ -964,6 +1021,12 @@ static bool __amp_capable(struct l2cap_chan *chan)
                return false;
 }
 
+static bool l2cap_check_efs(struct l2cap_chan *chan)
+{
+       /* Check EFS parameters */
+       return true;
+}
+
 void l2cap_send_conn_req(struct l2cap_chan *chan)
 {
        struct l2cap_conn *conn = chan->conn;
@@ -979,6 +1042,76 @@ void l2cap_send_conn_req(struct l2cap_chan *chan)
        l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_REQ, sizeof(req), &req);
 }
 
+static void l2cap_send_create_chan_req(struct l2cap_chan *chan, u8 amp_id)
+{
+       struct l2cap_create_chan_req req;
+       req.scid = cpu_to_le16(chan->scid);
+       req.psm  = chan->psm;
+       req.amp_id = amp_id;
+
+       chan->ident = l2cap_get_ident(chan->conn);
+
+       l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_REQ,
+                      sizeof(req), &req);
+}
+
+static void l2cap_move_setup(struct l2cap_chan *chan)
+{
+       struct sk_buff *skb;
+
+       BT_DBG("chan %p", chan);
+
+       if (chan->mode != L2CAP_MODE_ERTM)
+               return;
+
+       __clear_retrans_timer(chan);
+       __clear_monitor_timer(chan);
+       __clear_ack_timer(chan);
+
+       chan->retry_count = 0;
+       skb_queue_walk(&chan->tx_q, skb) {
+               if (bt_cb(skb)->control.retries)
+                       bt_cb(skb)->control.retries = 1;
+               else
+                       break;
+       }
+
+       chan->expected_tx_seq = chan->buffer_seq;
+
+       clear_bit(CONN_REJ_ACT, &chan->conn_state);
+       clear_bit(CONN_SREJ_ACT, &chan->conn_state);
+       l2cap_seq_list_clear(&chan->retrans_list);
+       l2cap_seq_list_clear(&chan->srej_list);
+       skb_queue_purge(&chan->srej_q);
+
+       chan->tx_state = L2CAP_TX_STATE_XMIT;
+       chan->rx_state = L2CAP_RX_STATE_MOVE;
+
+       set_bit(CONN_REMOTE_BUSY, &chan->conn_state);
+}
+
+static void l2cap_move_done(struct l2cap_chan *chan)
+{
+       u8 move_role = chan->move_role;
+       BT_DBG("chan %p", chan);
+
+       chan->move_state = L2CAP_MOVE_STABLE;
+       chan->move_role = L2CAP_MOVE_ROLE_NONE;
+
+       if (chan->mode != L2CAP_MODE_ERTM)
+               return;
+
+       switch (move_role) {
+       case L2CAP_MOVE_ROLE_INITIATOR:
+               l2cap_tx(chan, NULL, NULL, L2CAP_EV_EXPLICIT_POLL);
+               chan->rx_state = L2CAP_RX_STATE_WAIT_F;
+               break;
+       case L2CAP_MOVE_ROLE_RESPONDER:
+               chan->rx_state = L2CAP_RX_STATE_WAIT_P;
+               break;
+       }
+}
+
 static void l2cap_chan_ready(struct l2cap_chan *chan)
 {
        /* This clears all conf flags, including CONF_NOT_COMPLETE */
@@ -1695,6 +1828,9 @@ static void l2cap_streaming_send(struct l2cap_chan *chan,
 
        BT_DBG("chan %p, skbs %p", chan, skbs);
 
+       if (__chan_is_moving(chan))
+               return;
+
        skb_queue_splice_tail_init(skbs, &chan->tx_q);
 
        while (!skb_queue_empty(&chan->tx_q)) {
@@ -1737,6 +1873,9 @@ static int l2cap_ertm_send(struct l2cap_chan *chan)
        if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
                return 0;
 
+       if (__chan_is_moving(chan))
+               return 0;
+
        while (chan->tx_send_head &&
               chan->unacked_frames < chan->remote_tx_win &&
               chan->tx_state == L2CAP_TX_STATE_XMIT) {
@@ -1802,6 +1941,9 @@ static void l2cap_ertm_resend(struct l2cap_chan *chan)
        if (test_bit(CONN_REMOTE_BUSY, &chan->conn_state))
                return;
 
+       if (__chan_is_moving(chan))
+               return;
+
        while (chan->retrans_list.head != L2CAP_SEQ_LIST_CLEAR) {
                seq = l2cap_seq_list_pop(&chan->retrans_list);
 
@@ -2144,7 +2286,9 @@ static int l2cap_segment_sdu(struct l2cap_chan *chan,
        /* PDU size is derived from the HCI MTU */
        pdu_len = chan->conn->mtu;
 
-       pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
+       /* Constrain PDU size for BR/EDR connections */
+       if (!chan->hs_hcon)
+               pdu_len = min_t(size_t, pdu_len, L2CAP_BREDR_MAX_PAYLOAD);
 
        /* Adjust for largest possible L2CAP overhead. */
        if (chan->fcs)
@@ -2788,6 +2932,11 @@ int l2cap_ertm_init(struct l2cap_chan *chan)
 
        skb_queue_head_init(&chan->tx_q);
 
+       chan->local_amp_id = 0;
+       chan->move_id = 0;
+       chan->move_state = L2CAP_MOVE_STABLE;
+       chan->move_role = L2CAP_MOVE_ROLE_NONE;
+
        if (chan->mode != L2CAP_MODE_ERTM)
                return 0;
 
@@ -2834,6 +2983,44 @@ static inline bool __l2cap_efs_supported(struct l2cap_chan *chan)
        return enable_hs && chan->conn->feat_mask & L2CAP_FEAT_EXT_FLOW;
 }
 
+static void __l2cap_set_ertm_timeouts(struct l2cap_chan *chan,
+                                     struct l2cap_conf_rfc *rfc)
+{
+       if (chan->local_amp_id && chan->hs_hcon) {
+               u64 ertm_to = chan->hs_hcon->hdev->amp_be_flush_to;
+
+               /* Class 1 devices have must have ERTM timeouts
+                * exceeding the Link Supervision Timeout.  The
+                * default Link Supervision Timeout for AMP
+                * controllers is 10 seconds.
+                *
+                * Class 1 devices use 0xffffffff for their
+                * best-effort flush timeout, so the clamping logic
+                * will result in a timeout that meets the above
+                * requirement.  ERTM timeouts are 16-bit values, so
+                * the maximum timeout is 65.535 seconds.
+                */
+
+               /* Convert timeout to milliseconds and round */
+               ertm_to = DIV_ROUND_UP_ULL(ertm_to, 1000);
+
+               /* This is the recommended formula for class 2 devices
+                * that start ERTM timers when packets are sent to the
+                * controller.
+                */
+               ertm_to = 3 * ertm_to + 500;
+
+               if (ertm_to > 0xffff)
+                       ertm_to = 0xffff;
+
+               rfc->retrans_timeout = cpu_to_le16((u16) ertm_to);
+               rfc->monitor_timeout = rfc->retrans_timeout;
+       } else {
+               rfc->retrans_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
+               rfc->monitor_timeout = __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+       }
+}
+
 static inline void l2cap_txwin_setup(struct l2cap_chan *chan)
 {
        if (chan->tx_win > L2CAP_DEFAULT_TX_WINDOW &&
@@ -2900,8 +3087,8 @@ done:
        case L2CAP_MODE_ERTM:
                rfc.mode            = L2CAP_MODE_ERTM;
                rfc.max_transmit    = chan->max_tx;
-               rfc.retrans_timeout = 0;
-               rfc.monitor_timeout = 0;
+
+               __l2cap_set_ertm_timeouts(chan, &rfc);
 
                size = min_t(u16, L2CAP_DEFAULT_MAX_PDU_SIZE, chan->conn->mtu -
                             L2CAP_EXT_HDR_SIZE - L2CAP_SDULEN_SIZE -
@@ -3129,10 +3316,7 @@ done:
                        rfc.max_pdu_size = cpu_to_le16(size);
                        chan->remote_mps = size;
 
-                       rfc.retrans_timeout =
-                               __constant_cpu_to_le16(L2CAP_DEFAULT_RETRANS_TO);
-                       rfc.monitor_timeout =
-                               __constant_cpu_to_le16(L2CAP_DEFAULT_MONITOR_TO);
+                       __l2cap_set_ertm_timeouts(chan, &rfc);
 
                        set_bit(CONF_MODE_DONE, &chan->conf_state);
 
@@ -3308,12 +3492,21 @@ void __l2cap_connect_rsp_defer(struct l2cap_chan *chan)
        struct l2cap_conn_rsp rsp;
        struct l2cap_conn *conn = chan->conn;
        u8 buf[128];
+       u8 rsp_code;
 
        rsp.scid   = cpu_to_le16(chan->dcid);
        rsp.dcid   = cpu_to_le16(chan->scid);
        rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
        rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
-       l2cap_send_cmd(conn, chan->ident, L2CAP_CONN_RSP, sizeof(rsp), &rsp);
+
+       if (chan->hs_hcon)
+               rsp_code = L2CAP_CREATE_CHAN_RSP;
+       else
+               rsp_code = L2CAP_CONN_RSP;
+
+       BT_DBG("chan %p rsp_code %u", chan, rsp_code);
+
+       l2cap_send_cmd(conn, chan->ident, rsp_code, sizeof(rsp), &rsp);
 
        if (test_and_set_bit(CONF_REQ_SENT, &chan->conf_state))
                return;
@@ -3395,8 +3588,9 @@ static inline int l2cap_command_rej(struct l2cap_conn *conn,
        return 0;
 }
 
-static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
-                         u8 *data, u8 rsp_code, u8 amp_id)
+static struct l2cap_chan *l2cap_connect(struct l2cap_conn *conn,
+                                       struct l2cap_cmd_hdr *cmd,
+                                       u8 *data, u8 rsp_code, u8 amp_id)
 {
        struct l2cap_conn_req *req = (struct l2cap_conn_req *) data;
        struct l2cap_conn_rsp rsp;
@@ -3447,6 +3641,7 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
        bacpy(&bt_sk(sk)->dst, conn->dst);
        chan->psm  = psm;
        chan->dcid = scid;
+       chan->local_amp_id = amp_id;
 
        __l2cap_chan_add(conn, chan);
 
@@ -3464,8 +3659,17 @@ static void l2cap_connect(struct l2cap_conn *conn, struct l2cap_cmd_hdr *cmd,
                                status = L2CAP_CS_AUTHOR_PEND;
                                chan->ops->defer(chan);
                        } else {
-                               __l2cap_state_change(chan, BT_CONFIG);
-                               result = L2CAP_CR_SUCCESS;
+                               /* Force pending result for AMP controllers.
+                                * The connection will succeed after the
+                                * physical link is up.
+                                */
+                               if (amp_id) {
+                                       __l2cap_state_change(chan, BT_CONNECT2);
+                                       result = L2CAP_CR_PEND;
+                               } else {
+                                       __l2cap_state_change(chan, BT_CONFIG);
+                                       result = L2CAP_CR_SUCCESS;
+                               }
                                status = L2CAP_CS_NO_INFO;
                        }
                } else {
@@ -3511,6 +3715,8 @@ sendresp:
                               l2cap_build_conf_req(chan, buf), buf);
                chan->num_conf_req++;
        }
+
+       return chan;
 }
 
 static int l2cap_connect_req(struct l2cap_conn *conn,
@@ -3520,7 +3726,7 @@ static int l2cap_connect_req(struct l2cap_conn *conn,
        return 0;
 }
 
-static inline int l2cap_connect_rsp(struct l2cap_conn *conn,
+static int l2cap_connect_create_rsp(struct l2cap_conn *conn,
                                    struct l2cap_cmd_hdr *cmd, u8 *data)
 {
        struct l2cap_conn_rsp *rsp = (struct l2cap_conn_rsp *) data;
@@ -3675,6 +3881,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
                goto unlock;
        }
 
+       chan->ident = cmd->ident;
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CONF_RSP, len, rsp);
        chan->num_conf_rsp++;
 
@@ -3714,7 +3921,7 @@ static inline int l2cap_config_req(struct l2cap_conn *conn,
                /* check compatibility */
 
                /* Send rsp for BR/EDR channel */
-               if (!chan->ctrl_id)
+               if (!chan->hs_hcon)
                        l2cap_send_efs_conf_rsp(chan, rsp, cmd->ident, flags);
                else
                        chan->ident = cmd->ident;
@@ -3764,13 +3971,15 @@ static inline int l2cap_config_rsp(struct l2cap_conn *conn,
                                goto done;
                        }
 
-                       /* check compatibility */
-
-                       if (!chan->ctrl_id)
+                       if (!chan->hs_hcon) {
                                l2cap_send_efs_conf_rsp(chan, buf, cmd->ident,
                                                        0);
-                       else
-                               chan->ident = cmd->ident;
+                       } else {
+                               if (l2cap_check_efs(chan)) {
+                                       amp_create_logical_link(chan);
+                                       chan->ident = cmd->ident;
+                               }
+                       }
                }
                goto done;
 
@@ -4023,12 +4232,14 @@ static inline int l2cap_information_rsp(struct l2cap_conn *conn,
        return 0;
 }
 
-static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
-                                          struct l2cap_cmd_hdr *cmd,
-                                          u16 cmd_len, void *data)
+static int l2cap_create_channel_req(struct l2cap_conn *conn,
+                                   struct l2cap_cmd_hdr *cmd,
+                                   u16 cmd_len, void *data)
 {
        struct l2cap_create_chan_req *req = data;
        struct l2cap_create_chan_rsp rsp;
+       struct l2cap_chan *chan;
+       struct hci_dev *hdev;
        u16 psm, scid;
 
        if (cmd_len != sizeof(*req))
@@ -4042,57 +4253,119 @@ static inline int l2cap_create_channel_req(struct l2cap_conn *conn,
 
        BT_DBG("psm 0x%2.2x, scid 0x%4.4x, amp_id %d", psm, scid, req->amp_id);
 
-       /* Placeholder: Always reject */
+       /* For controller id 0 make BR/EDR connection */
+       if (req->amp_id == HCI_BREDR_ID) {
+               l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
+                             req->amp_id);
+               return 0;
+       }
+
+       /* Validate AMP controller id */
+       hdev = hci_dev_get(req->amp_id);
+       if (!hdev)
+               goto error;
+
+       if (hdev->dev_type != HCI_AMP || !test_bit(HCI_UP, &hdev->flags)) {
+               hci_dev_put(hdev);
+               goto error;
+       }
+
+       chan = l2cap_connect(conn, cmd, data, L2CAP_CREATE_CHAN_RSP,
+                            req->amp_id);
+       if (chan) {
+               struct amp_mgr *mgr = conn->hcon->amp_mgr;
+               struct hci_conn *hs_hcon;
+
+               hs_hcon = hci_conn_hash_lookup_ba(hdev, AMP_LINK, conn->dst);
+               if (!hs_hcon) {
+                       hci_dev_put(hdev);
+                       return -EFAULT;
+               }
+
+               BT_DBG("mgr %p bredr_chan %p hs_hcon %p", mgr, chan, hs_hcon);
+
+               mgr->bredr_chan = chan;
+               chan->hs_hcon = hs_hcon;
+               chan->fcs = L2CAP_FCS_NONE;
+               conn->mtu = hdev->block_mtu;
+       }
+
+       hci_dev_put(hdev);
+
+       return 0;
+
+error:
        rsp.dcid = 0;
        rsp.scid = cpu_to_le16(scid);
-       rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
+       rsp.result = __constant_cpu_to_le16(L2CAP_CR_BAD_AMP);
        rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
 
        l2cap_send_cmd(conn, cmd->ident, L2CAP_CREATE_CHAN_RSP,
                       sizeof(rsp), &rsp);
 
-       return 0;
+       return -EFAULT;
 }
 
-static inline int l2cap_create_channel_rsp(struct l2cap_conn *conn,
-                                          struct l2cap_cmd_hdr *cmd,
-                                          void *data)
+static void l2cap_send_move_chan_req(struct l2cap_chan *chan, u8 dest_amp_id)
 {
-       BT_DBG("conn %p", conn);
+       struct l2cap_move_chan_req req;
+       u8 ident;
+
+       BT_DBG("chan %p, dest_amp_id %d", chan, dest_amp_id);
+
+       ident = l2cap_get_ident(chan->conn);
+       chan->ident = ident;
 
-       return l2cap_connect_rsp(conn, cmd, data);
+       req.icid = cpu_to_le16(chan->scid);
+       req.dest_amp_id = dest_amp_id;
+
+       l2cap_send_cmd(chan->conn, ident, L2CAP_MOVE_CHAN_REQ, sizeof(req),
+                      &req);
+
+       __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
 }
 
-static void l2cap_send_move_chan_rsp(struct l2cap_conn *conn, u8 ident,
-                                    u16 icid, u16 result)
+static void l2cap_send_move_chan_rsp(struct l2cap_chan *chan, u16 result)
 {
        struct l2cap_move_chan_rsp rsp;
 
-       BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result);
+       BT_DBG("chan %p, result 0x%4.4x", chan, result);
 
-       rsp.icid = cpu_to_le16(icid);
+       rsp.icid = cpu_to_le16(chan->dcid);
        rsp.result = cpu_to_le16(result);
 
-       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_RSP, sizeof(rsp), &rsp);
+       l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_RSP,
+                      sizeof(rsp), &rsp);
 }
 
-static void l2cap_send_move_chan_cfm(struct l2cap_conn *conn,
-                                    struct l2cap_chan *chan,
-                                    u16 icid, u16 result)
+static void l2cap_send_move_chan_cfm(struct l2cap_chan *chan, u16 result)
 {
        struct l2cap_move_chan_cfm cfm;
-       u8 ident;
 
-       BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result);
+       BT_DBG("chan %p, result 0x%4.4x", chan, result);
 
-       ident = l2cap_get_ident(conn);
-       if (chan)
-               chan->ident = ident;
+       chan->ident = l2cap_get_ident(chan->conn);
 
-       cfm.icid = cpu_to_le16(icid);
+       cfm.icid = cpu_to_le16(chan->scid);
        cfm.result = cpu_to_le16(result);
 
-       l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM, sizeof(cfm), &cfm);
+       l2cap_send_cmd(chan->conn, chan->ident, L2CAP_MOVE_CHAN_CFM,
+                      sizeof(cfm), &cfm);
+
+       __set_chan_timer(chan, L2CAP_MOVE_TIMEOUT);
+}
+
+static void l2cap_send_move_chan_cfm_icid(struct l2cap_conn *conn, u16 icid)
+{
+       struct l2cap_move_chan_cfm cfm;
+
+       BT_DBG("conn %p, icid 0x%4.4x", conn, icid);
+
+       cfm.icid = cpu_to_le16(icid);
+       cfm.result = __constant_cpu_to_le16(L2CAP_MC_UNCONFIRMED);
+
+       l2cap_send_cmd(conn, l2cap_get_ident(conn), L2CAP_MOVE_CHAN_CFM,
+                      sizeof(cfm), &cfm);
 }
 
 static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
@@ -4106,11 +4379,289 @@ static void l2cap_send_move_chan_cfm_rsp(struct l2cap_conn *conn, u8 ident,
        l2cap_send_cmd(conn, ident, L2CAP_MOVE_CHAN_CFM_RSP, sizeof(rsp), &rsp);
 }
 
+static void __release_logical_link(struct l2cap_chan *chan)
+{
+       chan->hs_hchan = NULL;
+       chan->hs_hcon = NULL;
+
+       /* Placeholder - release the logical link */
+}
+
+static void l2cap_logical_fail(struct l2cap_chan *chan)
+{
+       /* Logical link setup failed */
+       if (chan->state != BT_CONNECTED) {
+               /* Create channel failure, disconnect */
+               l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
+               return;
+       }
+
+       switch (chan->move_role) {
+       case L2CAP_MOVE_ROLE_RESPONDER:
+               l2cap_move_done(chan);
+               l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_SUPP);
+               break;
+       case L2CAP_MOVE_ROLE_INITIATOR:
+               if (chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_COMP ||
+                   chan->move_state == L2CAP_MOVE_WAIT_LOGICAL_CFM) {
+                       /* Remote has only sent pending or
+                        * success responses, clean up
+                        */
+                       l2cap_move_done(chan);
+               }
+
+               /* Other amp move states imply that the move
+                * has already aborted
+                */
+               l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
+               break;
+       }
+}
+
+static void l2cap_logical_finish_create(struct l2cap_chan *chan,
+                                       struct hci_chan *hchan)
+{
+       struct l2cap_conf_rsp rsp;
+
+       chan->hs_hchan = hchan;
+       chan->hs_hcon->l2cap_data = chan->conn;
+
+       l2cap_send_efs_conf_rsp(chan, &rsp, chan->ident, 0);
+
+       if (test_bit(CONF_INPUT_DONE, &chan->conf_state)) {
+               int err;
+
+               set_default_fcs(chan);
+
+               err = l2cap_ertm_init(chan);
+               if (err < 0)
+                       l2cap_send_disconn_req(chan->conn, chan, -err);
+               else
+                       l2cap_chan_ready(chan);
+       }
+}
+
+static void l2cap_logical_finish_move(struct l2cap_chan *chan,
+                                     struct hci_chan *hchan)
+{
+       chan->hs_hcon = hchan->conn;
+       chan->hs_hcon->l2cap_data = chan->conn;
+
+       BT_DBG("move_state %d", chan->move_state);
+
+       switch (chan->move_state) {
+       case L2CAP_MOVE_WAIT_LOGICAL_COMP:
+               /* Move confirm will be sent after a success
+                * response is received
+                */
+               chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
+               break;
+       case L2CAP_MOVE_WAIT_LOGICAL_CFM:
+               if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+                       chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
+               } else if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
+                       chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP;
+                       l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED);
+               } else if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
+                       chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
+                       l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS);
+               }
+               break;
+       default:
+               /* Move was not in expected state, free the channel */
+               __release_logical_link(chan);
+
+               chan->move_state = L2CAP_MOVE_STABLE;
+       }
+}
+
+/* Call with chan locked */
+void l2cap_logical_cfm(struct l2cap_chan *chan, struct hci_chan *hchan,
+                      u8 status)
+{
+       BT_DBG("chan %p, hchan %p, status %d", chan, hchan, status);
+
+       if (status) {
+               l2cap_logical_fail(chan);
+               __release_logical_link(chan);
+               return;
+       }
+
+       if (chan->state != BT_CONNECTED) {
+               /* Ignore logical link if channel is on BR/EDR */
+               if (chan->local_amp_id)
+                       l2cap_logical_finish_create(chan, hchan);
+       } else {
+               l2cap_logical_finish_move(chan, hchan);
+       }
+}
+
+void l2cap_move_start(struct l2cap_chan *chan)
+{
+       BT_DBG("chan %p", chan);
+
+       if (chan->local_amp_id == HCI_BREDR_ID) {
+               if (chan->chan_policy != BT_CHANNEL_POLICY_AMP_PREFERRED)
+                       return;
+               chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
+               chan->move_state = L2CAP_MOVE_WAIT_PREPARE;
+               /* Placeholder - start physical link setup */
+       } else {
+               chan->move_role = L2CAP_MOVE_ROLE_INITIATOR;
+               chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
+               chan->move_id = 0;
+               l2cap_move_setup(chan);
+               l2cap_send_move_chan_req(chan, 0);
+       }
+}
+
+static void l2cap_do_create(struct l2cap_chan *chan, int result,
+                           u8 local_amp_id, u8 remote_amp_id)
+{
+       BT_DBG("chan %p state %s %u -> %u", chan, state_to_string(chan->state),
+              local_amp_id, remote_amp_id);
+
+       chan->fcs = L2CAP_FCS_NONE;
+
+       /* Outgoing channel on AMP */
+       if (chan->state == BT_CONNECT) {
+               if (result == L2CAP_CR_SUCCESS) {
+                       chan->local_amp_id = local_amp_id;
+                       l2cap_send_create_chan_req(chan, remote_amp_id);
+               } else {
+                       /* Revert to BR/EDR connect */
+                       l2cap_send_conn_req(chan);
+               }
+
+               return;
+       }
+
+       /* Incoming channel on AMP */
+       if (__l2cap_no_conn_pending(chan)) {
+               struct l2cap_conn_rsp rsp;
+               char buf[128];
+               rsp.scid = cpu_to_le16(chan->dcid);
+               rsp.dcid = cpu_to_le16(chan->scid);
+
+               if (result == L2CAP_CR_SUCCESS) {
+                       /* Send successful response */
+                       rsp.result = __constant_cpu_to_le16(L2CAP_CR_SUCCESS);
+                       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
+               } else {
+                       /* Send negative response */
+                       rsp.result = __constant_cpu_to_le16(L2CAP_CR_NO_MEM);
+                       rsp.status = __constant_cpu_to_le16(L2CAP_CS_NO_INFO);
+               }
+
+               l2cap_send_cmd(chan->conn, chan->ident, L2CAP_CREATE_CHAN_RSP,
+                              sizeof(rsp), &rsp);
+
+               if (result == L2CAP_CR_SUCCESS) {
+                       __l2cap_state_change(chan, BT_CONFIG);
+                       set_bit(CONF_REQ_SENT, &chan->conf_state);
+                       l2cap_send_cmd(chan->conn, l2cap_get_ident(chan->conn),
+                                      L2CAP_CONF_REQ,
+                                      l2cap_build_conf_req(chan, buf), buf);
+                       chan->num_conf_req++;
+               }
+       }
+}
+
+static void l2cap_do_move_initiate(struct l2cap_chan *chan, u8 local_amp_id,
+                                  u8 remote_amp_id)
+{
+       l2cap_move_setup(chan);
+       chan->move_id = local_amp_id;
+       chan->move_state = L2CAP_MOVE_WAIT_RSP;
+
+       l2cap_send_move_chan_req(chan, remote_amp_id);
+}
+
+static void l2cap_do_move_respond(struct l2cap_chan *chan, int result)
+{
+       struct hci_chan *hchan = NULL;
+
+       /* Placeholder - get hci_chan for logical link */
+
+       if (hchan) {
+               if (hchan->state == BT_CONNECTED) {
+                       /* Logical link is ready to go */
+                       chan->hs_hcon = hchan->conn;
+                       chan->hs_hcon->l2cap_data = chan->conn;
+                       chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
+                       l2cap_send_move_chan_rsp(chan, L2CAP_MR_SUCCESS);
+
+                       l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS);
+               } else {
+                       /* Wait for logical link to be ready */
+                       chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
+               }
+       } else {
+               /* Logical link not available */
+               l2cap_send_move_chan_rsp(chan, L2CAP_MR_NOT_ALLOWED);
+       }
+}
+
+static void l2cap_do_move_cancel(struct l2cap_chan *chan, int result)
+{
+       if (chan->move_role == L2CAP_MOVE_ROLE_RESPONDER) {
+               u8 rsp_result;
+               if (result == -EINVAL)
+                       rsp_result = L2CAP_MR_BAD_ID;
+               else
+                       rsp_result = L2CAP_MR_NOT_ALLOWED;
+
+               l2cap_send_move_chan_rsp(chan, rsp_result);
+       }
+
+       chan->move_role = L2CAP_MOVE_ROLE_NONE;
+       chan->move_state = L2CAP_MOVE_STABLE;
+
+       /* Restart data transmission */
+       l2cap_ertm_send(chan);
+}
+
+/* Invoke with locked chan */
+void __l2cap_physical_cfm(struct l2cap_chan *chan, int result)
+{
+       u8 local_amp_id = chan->local_amp_id;
+       u8 remote_amp_id = chan->remote_amp_id;
+
+       BT_DBG("chan %p, result %d, local_amp_id %d, remote_amp_id %d",
+              chan, result, local_amp_id, remote_amp_id);
+
+       if (chan->state == BT_DISCONN || chan->state == BT_CLOSED) {
+               l2cap_chan_unlock(chan);
+               return;
+       }
+
+       if (chan->state != BT_CONNECTED) {
+               l2cap_do_create(chan, result, local_amp_id, remote_amp_id);
+       } else if (result != L2CAP_MR_SUCCESS) {
+               l2cap_do_move_cancel(chan, result);
+       } else {
+               switch (chan->move_role) {
+               case L2CAP_MOVE_ROLE_INITIATOR:
+                       l2cap_do_move_initiate(chan, local_amp_id,
+                                              remote_amp_id);
+                       break;
+               case L2CAP_MOVE_ROLE_RESPONDER:
+                       l2cap_do_move_respond(chan, result);
+                       break;
+               default:
+                       l2cap_do_move_cancel(chan, result);
+                       break;
+               }
+       }
+}
+
 static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
                                         struct l2cap_cmd_hdr *cmd,
                                         u16 cmd_len, void *data)
 {
        struct l2cap_move_chan_req *req = data;
+       struct l2cap_move_chan_rsp rsp;
+       struct l2cap_chan *chan;
        u16 icid = 0;
        u16 result = L2CAP_MR_NOT_ALLOWED;
 
@@ -4124,15 +4675,206 @@ static inline int l2cap_move_channel_req(struct l2cap_conn *conn,
        if (!enable_hs)
                return -EINVAL;
 
-       /* Placeholder: Always refuse */
-       l2cap_send_move_chan_rsp(conn, cmd->ident, icid, result);
+       chan = l2cap_get_chan_by_dcid(conn, icid);
+       if (!chan) {
+               rsp.icid = cpu_to_le16(icid);
+               rsp.result = __constant_cpu_to_le16(L2CAP_MR_NOT_ALLOWED);
+               l2cap_send_cmd(conn, cmd->ident, L2CAP_MOVE_CHAN_RSP,
+                              sizeof(rsp), &rsp);
+               return 0;
+       }
+
+       chan->ident = cmd->ident;
+
+       if (chan->scid < L2CAP_CID_DYN_START ||
+           chan->chan_policy == BT_CHANNEL_POLICY_BREDR_ONLY ||
+           (chan->mode != L2CAP_MODE_ERTM &&
+            chan->mode != L2CAP_MODE_STREAMING)) {
+               result = L2CAP_MR_NOT_ALLOWED;
+               goto send_move_response;
+       }
+
+       if (chan->local_amp_id == req->dest_amp_id) {
+               result = L2CAP_MR_SAME_ID;
+               goto send_move_response;
+       }
+
+       if (req->dest_amp_id) {
+               struct hci_dev *hdev;
+               hdev = hci_dev_get(req->dest_amp_id);
+               if (!hdev || hdev->dev_type != HCI_AMP ||
+                   !test_bit(HCI_UP, &hdev->flags)) {
+                       if (hdev)
+                               hci_dev_put(hdev);
+
+                       result = L2CAP_MR_BAD_ID;
+                       goto send_move_response;
+               }
+               hci_dev_put(hdev);
+       }
+
+       /* Detect a move collision.  Only send a collision response
+        * if this side has "lost", otherwise proceed with the move.
+        * The winner has the larger bd_addr.
+        */
+       if ((__chan_is_moving(chan) ||
+            chan->move_role != L2CAP_MOVE_ROLE_NONE) &&
+           bacmp(conn->src, conn->dst) > 0) {
+               result = L2CAP_MR_COLLISION;
+               goto send_move_response;
+       }
+
+       chan->move_role = L2CAP_MOVE_ROLE_RESPONDER;
+       l2cap_move_setup(chan);
+       chan->move_id = req->dest_amp_id;
+       icid = chan->dcid;
+
+       if (!req->dest_amp_id) {
+               /* Moving to BR/EDR */
+               if (test_bit(CONN_LOCAL_BUSY, &chan->conn_state)) {
+                       chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
+                       result = L2CAP_MR_PEND;
+               } else {
+                       chan->move_state = L2CAP_MOVE_WAIT_CONFIRM;
+                       result = L2CAP_MR_SUCCESS;
+               }
+       } else {
+               chan->move_state = L2CAP_MOVE_WAIT_PREPARE;
+               /* Placeholder - uncomment when amp functions are available */
+               /*amp_accept_physical(chan, req->dest_amp_id);*/
+               result = L2CAP_MR_PEND;
+       }
+
+send_move_response:
+       l2cap_send_move_chan_rsp(chan, result);
+
+       l2cap_chan_unlock(chan);
 
        return 0;
 }
 
-static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
-                                        struct l2cap_cmd_hdr *cmd,
-                                        u16 cmd_len, void *data)
+static void l2cap_move_continue(struct l2cap_conn *conn, u16 icid, u16 result)
+{
+       struct l2cap_chan *chan;
+       struct hci_chan *hchan = NULL;
+
+       chan = l2cap_get_chan_by_scid(conn, icid);
+       if (!chan) {
+               l2cap_send_move_chan_cfm_icid(conn, icid);
+               return;
+       }
+
+       __clear_chan_timer(chan);
+       if (result == L2CAP_MR_PEND)
+               __set_chan_timer(chan, L2CAP_MOVE_ERTX_TIMEOUT);
+
+       switch (chan->move_state) {
+       case L2CAP_MOVE_WAIT_LOGICAL_COMP:
+               /* Move confirm will be sent when logical link
+                * is complete.
+                */
+               chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
+               break;
+       case L2CAP_MOVE_WAIT_RSP_SUCCESS:
+               if (result == L2CAP_MR_PEND) {
+                       break;
+               } else if (test_bit(CONN_LOCAL_BUSY,
+                                   &chan->conn_state)) {
+                       chan->move_state = L2CAP_MOVE_WAIT_LOCAL_BUSY;
+               } else {
+                       /* Logical link is up or moving to BR/EDR,
+                        * proceed with move
+                        */
+                       chan->move_state = L2CAP_MOVE_WAIT_CONFIRM_RSP;
+                       l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED);
+               }
+               break;
+       case L2CAP_MOVE_WAIT_RSP:
+               /* Moving to AMP */
+               if (result == L2CAP_MR_SUCCESS) {
+                       /* Remote is ready, send confirm immediately
+                        * after logical link is ready
+                        */
+                       chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_CFM;
+               } else {
+                       /* Both logical link and move success
+                        * are required to confirm
+                        */
+                       chan->move_state = L2CAP_MOVE_WAIT_LOGICAL_COMP;
+               }
+
+               /* Placeholder - get hci_chan for logical link */
+               if (!hchan) {
+                       /* Logical link not available */
+                       l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
+                       break;
+               }
+
+               /* If the logical link is not yet connected, do not
+                * send confirmation.
+                */
+               if (hchan->state != BT_CONNECTED)
+                       break;
+
+               /* Logical link is already ready to go */
+
+               chan->hs_hcon = hchan->conn;
+               chan->hs_hcon->l2cap_data = chan->conn;
+
+               if (result == L2CAP_MR_SUCCESS) {
+                       /* Can confirm now */
+                       l2cap_send_move_chan_cfm(chan, L2CAP_MC_CONFIRMED);
+               } else {
+                       /* Now only need move success
+                        * to confirm
+                        */
+                       chan->move_state = L2CAP_MOVE_WAIT_RSP_SUCCESS;
+               }
+
+               l2cap_logical_cfm(chan, hchan, L2CAP_MR_SUCCESS);
+               break;
+       default:
+               /* Any other amp move state means the move failed. */
+               chan->move_id = chan->local_amp_id;
+               l2cap_move_done(chan);
+               l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
+       }
+
+       l2cap_chan_unlock(chan);
+}
+
+static void l2cap_move_fail(struct l2cap_conn *conn, u8 ident, u16 icid,
+                           u16 result)
+{
+       struct l2cap_chan *chan;
+
+       chan = l2cap_get_chan_by_ident(conn, ident);
+       if (!chan) {
+               /* Could not locate channel, icid is best guess */
+               l2cap_send_move_chan_cfm_icid(conn, icid);
+               return;
+       }
+
+       __clear_chan_timer(chan);
+
+       if (chan->move_role == L2CAP_MOVE_ROLE_INITIATOR) {
+               if (result == L2CAP_MR_COLLISION) {
+                       chan->move_role = L2CAP_MOVE_ROLE_RESPONDER;
+               } else {
+                       /* Cleanup - cancel move */
+                       chan->move_id = chan->local_amp_id;
+                       l2cap_move_done(chan);
+               }
+       }
+
+       l2cap_send_move_chan_cfm(chan, L2CAP_MC_UNCONFIRMED);
+
+       l2cap_chan_unlock(chan);
+}
+
+static int l2cap_move_channel_rsp(struct l2cap_conn *conn,
+                                 struct l2cap_cmd_hdr *cmd,
+                                 u16 cmd_len, void *data)
 {
        struct l2cap_move_chan_rsp *rsp = data;
        u16 icid, result;
@@ -4145,17 +4887,20 @@ static inline int l2cap_move_channel_rsp(struct l2cap_conn *conn,
 
        BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result);
 
-       /* Placeholder: Always unconfirmed */
-       l2cap_send_move_chan_cfm(conn, NULL, icid, L2CAP_MC_UNCONFIRMED);
+       if (result == L2CAP_MR_SUCCESS || result == L2CAP_MR_PEND)
+               l2cap_move_continue(conn, icid, result);
+       else
+               l2cap_move_fail(conn, cmd->ident, icid, result);
 
        return 0;
 }
 
-static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
-                                            struct l2cap_cmd_hdr *cmd,
-                                            u16 cmd_len, void *data)
+static int l2cap_move_channel_confirm(struct l2cap_conn *conn,
+                                     struct l2cap_cmd_hdr *cmd,
+                                     u16 cmd_len, void *data)
 {
        struct l2cap_move_chan_cfm *cfm = data;
+       struct l2cap_chan *chan;
        u16 icid, result;
 
        if (cmd_len != sizeof(*cfm))
@@ -4166,8 +4911,29 @@ static inline int l2cap_move_channel_confirm(struct l2cap_conn *conn,
 
        BT_DBG("icid 0x%4.4x, result 0x%4.4x", icid, result);
 
+       chan = l2cap_get_chan_by_dcid(conn, icid);
+       if (!chan) {
+               /* Spec requires a response even if the icid was not found */
+               l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
+               return 0;
+       }
+
+       if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM) {
+               if (result == L2CAP_MC_CONFIRMED) {
+                       chan->local_amp_id = chan->move_id;
+                       if (!chan->local_amp_id)
+                               __release_logical_link(chan);
+               } else {
+                       chan->move_id = chan->local_amp_id;
+               }
+
+               l2cap_move_done(chan);
+       }
+
        l2cap_send_move_chan_cfm_rsp(conn, cmd->ident, icid);
 
+       l2cap_chan_unlock(chan);
+
        return 0;
 }
 
@@ -4176,6 +4942,7 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
                                                 u16 cmd_len, void *data)
 {
        struct l2cap_move_chan_cfm_rsp *rsp = data;
+       struct l2cap_chan *chan;
        u16 icid;
 
        if (cmd_len != sizeof(*rsp))
@@ -4185,6 +4952,23 @@ static inline int l2cap_move_channel_confirm_rsp(struct l2cap_conn *conn,
 
        BT_DBG("icid 0x%4.4x", icid);
 
+       chan = l2cap_get_chan_by_scid(conn, icid);
+       if (!chan)
+               return 0;
+
+       __clear_chan_timer(chan);
+
+       if (chan->move_state == L2CAP_MOVE_WAIT_CONFIRM_RSP) {
+               chan->local_amp_id = chan->move_id;
+
+               if (!chan->local_amp_id && chan->hs_hchan)
+                       __release_logical_link(chan);
+
+               l2cap_move_done(chan);
+       }
+
+       l2cap_chan_unlock(chan);
+
        return 0;
 }
 
@@ -4269,7 +5053,7 @@ static inline int l2cap_bredr_sig_cmd(struct l2cap_conn *conn,
 
        case L2CAP_CONN_RSP:
        case L2CAP_CREATE_CHAN_RSP:
-               err = l2cap_connect_rsp(conn, cmd, data);
+               err = l2cap_connect_create_rsp(conn, cmd, data);
                break;
 
        case L2CAP_CONF_REQ:
@@ -4556,6 +5340,12 @@ static int l2cap_reassemble_sdu(struct l2cap_chan *chan, struct sk_buff *skb,
        return err;
 }
 
+static int l2cap_resegment(struct l2cap_chan *chan)
+{
+       /* Placeholder */
+       return 0;
+}
+
 void l2cap_chan_busy(struct l2cap_chan *chan, int busy)
 {
        u8 event;
@@ -4871,8 +5661,8 @@ static int l2cap_rx_state_recv(struct l2cap_chan *chan,
                if (control->final) {
                        clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
 
-                       if (!test_and_clear_bit(CONN_REJ_ACT,
-                                               &chan->conn_state)) {
+                       if (!test_and_clear_bit(CONN_REJ_ACT, &chan->conn_state) &&
+                           !__chan_is_moving(chan)) {
                                control->final = 0;
                                l2cap_retransmit_all(chan, control);
                        }
@@ -5061,6 +5851,96 @@ static int l2cap_rx_state_srej_sent(struct l2cap_chan *chan,
        return err;
 }
 
+static int l2cap_finish_move(struct l2cap_chan *chan)
+{
+       BT_DBG("chan %p", chan);
+
+       chan->rx_state = L2CAP_RX_STATE_RECV;
+
+       if (chan->hs_hcon)
+               chan->conn->mtu = chan->hs_hcon->hdev->block_mtu;
+       else
+               chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
+
+       return l2cap_resegment(chan);
+}
+
+static int l2cap_rx_state_wait_p(struct l2cap_chan *chan,
+                                struct l2cap_ctrl *control,
+                                struct sk_buff *skb, u8 event)
+{
+       int err;
+
+       BT_DBG("chan %p, control %p, skb %p, event %d", chan, control, skb,
+              event);
+
+       if (!control->poll)
+               return -EPROTO;
+
+       l2cap_process_reqseq(chan, control->reqseq);
+
+       if (!skb_queue_empty(&chan->tx_q))
+               chan->tx_send_head = skb_peek(&chan->tx_q);
+       else
+               chan->tx_send_head = NULL;
+
+       /* Rewind next_tx_seq to the point expected
+        * by the receiver.
+        */
+       chan->next_tx_seq = control->reqseq;
+       chan->unacked_frames = 0;
+
+       err = l2cap_finish_move(chan);
+       if (err)
+               return err;
+
+       set_bit(CONN_SEND_FBIT, &chan->conn_state);
+       l2cap_send_i_or_rr_or_rnr(chan);
+
+       if (event == L2CAP_EV_RECV_IFRAME)
+               return -EPROTO;
+
+       return l2cap_rx_state_recv(chan, control, NULL, event);
+}
+
+static int l2cap_rx_state_wait_f(struct l2cap_chan *chan,
+                                struct l2cap_ctrl *control,
+                                struct sk_buff *skb, u8 event)
+{
+       int err;
+
+       if (!control->final)
+               return -EPROTO;
+
+       clear_bit(CONN_REMOTE_BUSY, &chan->conn_state);
+
+       chan->rx_state = L2CAP_RX_STATE_RECV;
+       l2cap_process_reqseq(chan, control->reqseq);
+
+       if (!skb_queue_empty(&chan->tx_q))
+               chan->tx_send_head = skb_peek(&chan->tx_q);
+       else
+               chan->tx_send_head = NULL;
+
+       /* Rewind next_tx_seq to the point expected
+        * by the receiver.
+        */
+       chan->next_tx_seq = control->reqseq;
+       chan->unacked_frames = 0;
+
+       if (chan->hs_hcon)
+               chan->conn->mtu = chan->hs_hcon->hdev->block_mtu;
+       else
+               chan->conn->mtu = chan->conn->hcon->hdev->acl_mtu;
+
+       err = l2cap_resegment(chan);
+
+       if (!err)
+               err = l2cap_rx_state_recv(chan, control, skb, event);
+
+       return err;
+}
+
 static bool __valid_reqseq(struct l2cap_chan *chan, u16 reqseq)
 {
        /* Make sure reqseq is for a packet that has been sent but not acked */
@@ -5087,6 +5967,12 @@ static int l2cap_rx(struct l2cap_chan *chan, struct l2cap_ctrl *control,
                        err = l2cap_rx_state_srej_sent(chan, control, skb,
                                                       event);
                        break;
+               case L2CAP_RX_STATE_WAIT_P:
+                       err = l2cap_rx_state_wait_p(chan, control, skb, event);
+                       break;
+               case L2CAP_RX_STATE_WAIT_F:
+                       err = l2cap_rx_state_wait_f(chan, control, skb, event);
+                       break;
                default:
                        /* shut it down */
                        break;
@@ -5206,7 +6092,7 @@ static int l2cap_data_rcv(struct l2cap_chan *chan, struct sk_buff *skb)
                       control->super);
 
                if (len != 0) {
-                       BT_ERR("%d", len);
+                       BT_ERR("Trailing bytes: %d in sframe", len);
                        l2cap_send_disconn_req(chan->conn, chan, ECONNRESET);
                        goto drop;
                }
@@ -5422,9 +6308,9 @@ void l2cap_connect_cfm(struct hci_conn *hcon, u8 status)
                conn = l2cap_conn_add(hcon, status);
                if (conn)
                        l2cap_conn_ready(conn);
-       } else
+       } else {
                l2cap_conn_del(hcon, bt_to_errno(status));
-
+       }
 }
 
 int l2cap_disconn_ind(struct hci_conn *hcon)
@@ -5500,7 +6386,7 @@ int l2cap_security_cfm(struct hci_conn *hcon, u8 status, u8 encrypt)
                        continue;
                }
 
-               if (test_bit(CONF_CONNECT_PEND, &chan->conf_state)) {
+               if (!__l2cap_no_conn_pending(chan)) {
                        l2cap_chan_unlock(chan);
                        continue;
                }
index 89f1472939ecfba8658c668506f8ce980f9a9866..1bcfb8422fdcf55096e9b4131e07eab63d5c365c 100644 (file)
@@ -736,6 +736,11 @@ static int l2cap_sock_setsockopt(struct socket *sock, int level, int optname,
                }
 
                chan->chan_policy = (u8) opt;
+
+               if (sk->sk_state == BT_CONNECTED &&
+                   chan->move_role == L2CAP_MOVE_ROLE_NONE)
+                       l2cap_move_start(chan);
+
                break;
 
        default:
index 158a87bb0c0d419755765b36c19e8441daceb407..142764aec2af6d4d7e6d5654e46e473c37c0218c 100644 (file)
@@ -222,7 +222,7 @@ static int cmd_status(struct sock *sk, u16 index, u16 cmd, u8 status)
 
        hdr = (void *) skb_put(skb, sizeof(*hdr));
 
-       hdr->opcode = cpu_to_le16(MGMT_EV_CMD_STATUS);
+       hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_STATUS);
        hdr->index = cpu_to_le16(index);
        hdr->len = cpu_to_le16(sizeof(*ev));
 
@@ -253,7 +253,7 @@ static int cmd_complete(struct sock *sk, u16 index, u16 cmd, u8 status,
 
        hdr = (void *) skb_put(skb, sizeof(*hdr));
 
-       hdr->opcode = cpu_to_le16(MGMT_EV_CMD_COMPLETE);
+       hdr->opcode = __constant_cpu_to_le16(MGMT_EV_CMD_COMPLETE);
        hdr->index = cpu_to_le16(index);
        hdr->len = cpu_to_le16(sizeof(*ev) + rp_len);
 
@@ -377,15 +377,15 @@ static u32 get_supported_settings(struct hci_dev *hdev)
        u32 settings = 0;
 
        settings |= MGMT_SETTING_POWERED;
-       settings |= MGMT_SETTING_CONNECTABLE;
-       settings |= MGMT_SETTING_FAST_CONNECTABLE;
-       settings |= MGMT_SETTING_DISCOVERABLE;
        settings |= MGMT_SETTING_PAIRABLE;
 
        if (lmp_ssp_capable(hdev))
                settings |= MGMT_SETTING_SSP;
 
        if (lmp_bredr_capable(hdev)) {
+               settings |= MGMT_SETTING_CONNECTABLE;
+               settings |= MGMT_SETTING_FAST_CONNECTABLE;
+               settings |= MGMT_SETTING_DISCOVERABLE;
                settings |= MGMT_SETTING_BREDR;
                settings |= MGMT_SETTING_LINK_SECURITY;
        }
@@ -485,7 +485,7 @@ static void create_eir(struct hci_dev *hdev, u8 *data)
                ptr += (name_len + 2);
        }
 
-       if (hdev->inq_tx_power) {
+       if (hdev->inq_tx_power != HCI_TX_POWER_INVALID) {
                ptr[0] = 2;
                ptr[1] = EIR_TX_POWER;
                ptr[2] = (u8) hdev->inq_tx_power;
@@ -566,7 +566,7 @@ static int update_eir(struct hci_dev *hdev)
        if (!hdev_is_powered(hdev))
                return 0;
 
-       if (!(hdev->features[6] & LMP_EXT_INQ))
+       if (!lmp_ext_inq_capable(hdev))
                return 0;
 
        if (!test_bit(HCI_SSP_ENABLED, &hdev->dev_flags))
@@ -833,7 +833,7 @@ static int mgmt_event(u16 event, struct hci_dev *hdev, void *data, u16 data_len,
        if (hdev)
                hdr->index = cpu_to_le16(hdev->id);
        else
-               hdr->index = cpu_to_le16(MGMT_INDEX_NONE);
+               hdr->index = __constant_cpu_to_le16(MGMT_INDEX_NONE);
        hdr->len = cpu_to_le16(data_len);
 
        if (data)
@@ -868,6 +868,10 @@ static int set_discoverable(struct sock *sk, struct hci_dev *hdev, void *data,
 
        BT_DBG("request for %s", hdev->name);
 
+       if (!lmp_bredr_capable(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
+                                MGMT_STATUS_NOT_SUPPORTED);
+
        timeout = __le16_to_cpu(cp->timeout);
        if (!cp->val && timeout > 0)
                return cmd_status(sk, hdev->id, MGMT_OP_SET_DISCOVERABLE,
@@ -963,6 +967,10 @@ static int set_connectable(struct sock *sk, struct hci_dev *hdev, void *data,
 
        BT_DBG("request for %s", hdev->name);
 
+       if (!lmp_bredr_capable(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_CONNECTABLE,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
        hci_dev_lock(hdev);
 
        if (!hdev_is_powered(hdev)) {
@@ -1061,6 +1069,10 @@ static int set_link_security(struct sock *sk, struct hci_dev *hdev, void *data,
 
        BT_DBG("request for %s", hdev->name);
 
+       if (!lmp_bredr_capable(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_LINK_SECURITY,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
        hci_dev_lock(hdev);
 
        if (!hdev_is_powered(hdev)) {
@@ -1214,7 +1226,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
        }
 
        val = !!cp->val;
-       enabled = !!(hdev->host_features[0] & LMP_HOST_LE);
+       enabled = !!lmp_host_le_capable(hdev);
 
        if (!hdev_is_powered(hdev) || val == enabled) {
                bool changed = false;
@@ -1250,7 +1262,7 @@ static int set_le(struct sock *sk, struct hci_dev *hdev, void *data, u16 len)
 
        if (val) {
                hci_cp.le = val;
-               hci_cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
+               hci_cp.simul = !!lmp_le_br_capable(hdev);
        }
 
        err = hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED, sizeof(hci_cp),
@@ -2596,6 +2608,10 @@ static int set_fast_connectable(struct sock *sk, struct hci_dev *hdev,
 
        BT_DBG("%s", hdev->name);
 
+       if (!lmp_bredr_capable(hdev))
+               return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
+                                 MGMT_STATUS_NOT_SUPPORTED);
+
        if (!hdev_is_powered(hdev))
                return cmd_status(sk, hdev->id, MGMT_OP_SET_FAST_CONNECTABLE,
                                  MGMT_STATUS_NOT_POWERED);
@@ -2873,6 +2889,21 @@ static void settings_rsp(struct pending_cmd *cmd, void *data)
        mgmt_pending_free(cmd);
 }
 
+static int set_bredr_scan(struct hci_dev *hdev)
+{
+       u8 scan = 0;
+
+       if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
+               scan |= SCAN_PAGE;
+       if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
+               scan |= SCAN_INQUIRY;
+
+       if (!scan)
+               return 0;
+
+       return hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
+}
+
 int mgmt_powered(struct hci_dev *hdev, u8 powered)
 {
        struct cmd_lookup match = { NULL, hdev };
@@ -2884,17 +2915,8 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
        mgmt_pending_foreach(MGMT_OP_SET_POWERED, hdev, settings_rsp, &match);
 
        if (powered) {
-               u8 scan = 0;
-
-               if (test_bit(HCI_CONNECTABLE, &hdev->dev_flags))
-                       scan |= SCAN_PAGE;
-               if (test_bit(HCI_DISCOVERABLE, &hdev->dev_flags))
-                       scan |= SCAN_INQUIRY;
-
-               if (scan)
-                       hci_send_cmd(hdev, HCI_OP_WRITE_SCAN_ENABLE, 1, &scan);
-
-               if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags)) {
+               if (test_bit(HCI_SSP_ENABLED, &hdev->dev_flags) &&
+                   !lmp_host_ssp_capable(hdev)) {
                        u8 ssp = 1;
 
                        hci_send_cmd(hdev, HCI_OP_WRITE_SSP_MODE, 1, &ssp);
@@ -2904,15 +2926,24 @@ int mgmt_powered(struct hci_dev *hdev, u8 powered)
                        struct hci_cp_write_le_host_supported cp;
 
                        cp.le = 1;
-                       cp.simul = !!(hdev->features[6] & LMP_SIMUL_LE_BR);
-
-                       hci_send_cmd(hdev, HCI_OP_WRITE_LE_HOST_SUPPORTED,
-                                    sizeof(cp), &cp);
+                       cp.simul = !!lmp_le_br_capable(hdev);
+
+                       /* Check first if we already have the right
+                        * host state (host features set)
+                        */
+                       if (cp.le != !!lmp_host_le_capable(hdev) ||
+                           cp.simul != !!lmp_host_le_br_capable(hdev))
+                               hci_send_cmd(hdev,
+                                            HCI_OP_WRITE_LE_HOST_SUPPORTED,
+                                            sizeof(cp), &cp);
                }
 
-               update_class(hdev);
-               update_name(hdev, hdev->dev_name);
-               update_eir(hdev);
+               if (lmp_bredr_capable(hdev)) {
+                       set_bredr_scan(hdev);
+                       update_class(hdev);
+                       update_name(hdev, hdev->dev_name);
+                       update_eir(hdev);
+               }
        } else {
                u8 status = MGMT_STATUS_NOT_POWERED;
                mgmt_pending_foreach(0, hdev, cmd_status_rsp, &status);
@@ -3361,7 +3392,7 @@ static int clear_eir(struct hci_dev *hdev)
 {
        struct hci_cp_write_eir cp;
 
-       if (!(hdev->features[6] & LMP_EXT_INQ))
+       if (!lmp_ext_inq_capable(hdev))
                return 0;
 
        memset(hdev->eir, 0, sizeof(hdev->eir));
@@ -3493,7 +3524,12 @@ send_event:
                err = mgmt_event(MGMT_EV_LOCAL_NAME_CHANGED, hdev, &ev,
                                 sizeof(ev), cmd ? cmd->sk : NULL);
 
-       update_eir(hdev);
+       /* EIR is taken care of separately when powering on the
+        * adapter so only update them here if this is a name change
+        * unrelated to power on.
+        */
+       if (!test_bit(HCI_INIT, &hdev->flags))
+               update_eir(hdev);
 
 failed:
        if (cmd)
@@ -3588,9 +3624,9 @@ int mgmt_device_found(struct hci_dev *hdev, bdaddr_t *bdaddr, u8 link_type,
        ev->addr.type = link_to_bdaddr(link_type, addr_type);
        ev->rssi = rssi;
        if (cfm_name)
-               ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
+               ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_CONFIRM_NAME);
        if (!ssp)
-               ev->flags |= cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
+               ev->flags |= __constant_cpu_to_le32(MGMT_DEV_FOUND_LEGACY_PAIRING);
 
        if (eir_len > 0)
                memcpy(ev->eir, eir, eir_len);
index 493353534a0f2c05ef4ad3912c0b91394a5bfcc8..537488cbf941a3699ccaf533d8a9bb92c9788434 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/types.h>
 #include <linux/crypto.h>
+#include <linux/export.h>
 #include <linux/err.h>
 #include <crypto/aes.h>
 
index 186d9919b043cc41fbaea7aee56e0cb5e688bf94..808338a1bce54666284c9b8f0c6c6c372d71326c 100644 (file)
@@ -118,7 +118,7 @@ void ieee80211_stop_rx_ba_session(struct ieee80211_vif *vif, u16 ba_rx_bitmap,
                return;
        }
 
-       for (i = 0; i < STA_TID_NUM; i++)
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++)
                if (ba_rx_bitmap & BIT(i))
                        set_bit(i, sta->ampdu_mlme.tid_rx_stop_requested);
 
index 3195a6307f50eeb5e6715a6db0fbecc4fee2f4d5..4152ed1034b8204ba3288470ac4fad890d65ed9c 100644 (file)
@@ -448,7 +448,7 @@ int ieee80211_start_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid,
        if (WARN_ON(!local->ops->ampdu_action))
                return -EINVAL;
 
-       if ((tid >= STA_TID_NUM) ||
+       if ((tid >= IEEE80211_NUM_TIDS) ||
            !(local->hw.flags & IEEE80211_HW_AMPDU_AGGREGATION) ||
            (local->hw.flags & IEEE80211_HW_TX_AMPDU_SETUP_IN_HW))
                return -EINVAL;
@@ -605,9 +605,9 @@ void ieee80211_start_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u16 tid)
 
        trace_api_start_tx_ba_cb(sdata, ra, tid);
 
-       if (tid >= STA_TID_NUM) {
+       if (tid >= IEEE80211_NUM_TIDS) {
                ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
-                      tid, STA_TID_NUM);
+                      tid, IEEE80211_NUM_TIDS);
                return;
        }
 
@@ -687,7 +687,7 @@ int ieee80211_stop_tx_ba_session(struct ieee80211_sta *pubsta, u16 tid)
        if (!local->ops->ampdu_action)
                return -EINVAL;
 
-       if (tid >= STA_TID_NUM)
+       if (tid >= IEEE80211_NUM_TIDS)
                return -EINVAL;
 
        spin_lock_bh(&sta->lock);
@@ -722,9 +722,9 @@ void ieee80211_stop_tx_ba_cb(struct ieee80211_vif *vif, u8 *ra, u8 tid)
 
        trace_api_stop_tx_ba_cb(sdata, ra, tid);
 
-       if (tid >= STA_TID_NUM) {
+       if (tid >= IEEE80211_NUM_TIDS) {
                ht_dbg(sdata, "Bad TID value: tid = %d (>= %d)\n",
-                      tid, STA_TID_NUM);
+                      tid, IEEE80211_NUM_TIDS);
                return;
        }
 
index 76690020d605ae5bbdd6cea45fe51af48040da0a..4965aa6424ecd02ef3d462d0eb216e2b3f1a4338 100644 (file)
@@ -370,30 +370,32 @@ static int ieee80211_config_default_mgmt_key(struct wiphy *wiphy,
        return 0;
 }
 
-static void rate_idx_to_bitrate(struct rate_info *rate, struct sta_info *sta, int idx)
-{
-       enum ieee80211_band band = ieee80211_get_sdata_band(sta->sdata);
-
-       if (!(rate->flags & RATE_INFO_FLAGS_MCS)) {
-               struct ieee80211_supported_band *sband;
-               sband = sta->local->hw.wiphy->bands[band];
-               rate->legacy = sband->bitrates[idx].bitrate;
-       } else
-               rate->mcs = idx;
-}
-
 void sta_set_rate_info_tx(struct sta_info *sta,
                          const struct ieee80211_tx_rate *rate,
                          struct rate_info *rinfo)
 {
        rinfo->flags = 0;
-       if (rate->flags & IEEE80211_TX_RC_MCS)
+       if (rate->flags & IEEE80211_TX_RC_MCS) {
                rinfo->flags |= RATE_INFO_FLAGS_MCS;
+               rinfo->mcs = rate->idx;
+       } else if (rate->flags & IEEE80211_TX_RC_VHT_MCS) {
+               rinfo->flags |= RATE_INFO_FLAGS_VHT_MCS;
+               rinfo->mcs = ieee80211_rate_get_vht_mcs(rate);
+               rinfo->nss = ieee80211_rate_get_vht_nss(rate);
+       } else {
+               struct ieee80211_supported_band *sband;
+               sband = sta->local->hw.wiphy->bands[
+                               ieee80211_get_sdata_band(sta->sdata)];
+               rinfo->legacy = sband->bitrates[rate->idx].bitrate;
+       }
        if (rate->flags & IEEE80211_TX_RC_40_MHZ_WIDTH)
                rinfo->flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+       if (rate->flags & IEEE80211_TX_RC_80_MHZ_WIDTH)
+               rinfo->flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+       if (rate->flags & IEEE80211_TX_RC_160_MHZ_WIDTH)
+               rinfo->flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
        if (rate->flags & IEEE80211_TX_RC_SHORT_GI)
                rinfo->flags |= RATE_INFO_FLAGS_SHORT_GI;
-       rate_idx_to_bitrate(rinfo, sta, rate->idx);
 }
 
 static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
@@ -444,13 +446,32 @@ static void sta_set_sinfo(struct sta_info *sta, struct station_info *sinfo)
        sta_set_rate_info_tx(sta, &sta->last_tx_rate, &sinfo->txrate);
 
        sinfo->rxrate.flags = 0;
-       if (sta->last_rx_rate_flag & RX_FLAG_HT)
+       if (sta->last_rx_rate_flag & RX_FLAG_HT) {
                sinfo->rxrate.flags |= RATE_INFO_FLAGS_MCS;
+               sinfo->rxrate.mcs = sta->last_rx_rate_idx;
+       } else if (sta->last_rx_rate_flag & RX_FLAG_VHT) {
+               sinfo->rxrate.flags |= RATE_INFO_FLAGS_VHT_MCS;
+               sinfo->rxrate.nss = sta->last_rx_rate_vht_nss;
+               sinfo->rxrate.mcs = sta->last_rx_rate_idx;
+       } else {
+               struct ieee80211_supported_band *sband;
+
+               sband = sta->local->hw.wiphy->bands[
+                               ieee80211_get_sdata_band(sta->sdata)];
+               sinfo->rxrate.legacy =
+                       sband->bitrates[sta->last_rx_rate_idx].bitrate;
+       }
+
        if (sta->last_rx_rate_flag & RX_FLAG_40MHZ)
                sinfo->rxrate.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
        if (sta->last_rx_rate_flag & RX_FLAG_SHORT_GI)
                sinfo->rxrate.flags |= RATE_INFO_FLAGS_SHORT_GI;
-       rate_idx_to_bitrate(&sinfo->rxrate, sta, sta->last_rx_rate_idx);
+       if (sta->last_rx_rate_flag & RX_FLAG_80MHZ)
+               sinfo->rxrate.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+       if (sta->last_rx_rate_flag & RX_FLAG_80P80MHZ)
+               sinfo->rxrate.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
+       if (sta->last_rx_rate_flag & RX_FLAG_160MHZ)
+               sinfo->rxrate.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
 
        if (ieee80211_vif_is_mesh(&sdata->vif)) {
 #ifdef CONFIG_MAC80211_MESH
@@ -615,7 +636,7 @@ do_survey:
        rcu_read_lock();
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (chanctx_conf)
-               channel = chanctx_conf->channel;
+               channel = chanctx_conf->def.chan;
        else
                channel = NULL;
        rcu_read_unlock();
@@ -735,15 +756,13 @@ static int ieee80211_get_station(struct wiphy *wiphy, struct net_device *dev,
 }
 
 static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
-                                        struct ieee80211_channel *chan,
-                                        enum nl80211_channel_type channel_type)
+                                        struct cfg80211_chan_def *chandef)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
        struct ieee80211_sub_if_data *sdata;
        int ret = 0;
 
-       if (local->monitor_channel == chan &&
-           local->monitor_channel_type == channel_type)
+       if (cfg80211_chandef_identical(&local->monitor_chandef, chandef))
                return 0;
 
        mutex_lock(&local->iflist_mtx);
@@ -753,20 +772,17 @@ static int ieee80211_set_monitor_channel(struct wiphy *wiphy,
                                lockdep_is_held(&local->iflist_mtx));
                if (sdata) {
                        ieee80211_vif_release_channel(sdata);
-                       ret = ieee80211_vif_use_channel(
-                                       sdata, chan, channel_type,
+                       ret = ieee80211_vif_use_channel(sdata, chandef,
                                        IEEE80211_CHANCTX_EXCLUSIVE);
                }
        } else if (local->open_count == local->monitors) {
-               local->_oper_channel = chan;
-               local->_oper_channel_type = channel_type;
+               local->_oper_channel = chandef->chan;
+               local->_oper_channel_type = cfg80211_get_chandef_type(chandef);
                ieee80211_hw_config(local, 0);
        }
 
-       if (ret == 0) {
-               local->monitor_channel = chan;
-               local->monitor_channel_type = channel_type;
-       }
+       if (ret == 0)
+               local->monitor_chandef = *chandef;
        mutex_unlock(&local->iflist_mtx);
 
        return ret;
@@ -888,8 +904,7 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = sdata->local->rx_chains;
 
-       err = ieee80211_vif_use_channel(sdata, params->channel,
-                                       params->channel_type,
+       err = ieee80211_vif_use_channel(sdata, &params->chandef,
                                        IEEE80211_CHANCTX_SHARED);
        if (err)
                return err;
@@ -922,6 +937,15 @@ static int ieee80211_start_ap(struct wiphy *wiphy, struct net_device *dev,
                return err;
        changed |= err;
 
+       err = drv_start_ap(sdata->local, sdata);
+       if (err) {
+               old = rtnl_dereference(sdata->u.ap.beacon);
+               if (old)
+                       kfree_rcu(old, rcu_head);
+               RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
+               return err;
+       }
+
        ieee80211_bss_info_change_notify(sdata, changed);
 
        netif_carrier_on(dev);
@@ -953,26 +977,38 @@ static int ieee80211_change_beacon(struct wiphy *wiphy, struct net_device *dev,
 
 static int ieee80211_stop_ap(struct wiphy *wiphy, struct net_device *dev)
 {
-       struct ieee80211_sub_if_data *sdata, *vlan;
-       struct beacon_data *old;
-
-       sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+       struct ieee80211_sub_if_data *vlan;
+       struct ieee80211_local *local = sdata->local;
+       struct beacon_data *old_beacon;
+       struct probe_resp *old_probe_resp;
 
-       old = rtnl_dereference(sdata->u.ap.beacon);
-       if (!old)
+       old_beacon = rtnl_dereference(sdata->u.ap.beacon);
+       if (!old_beacon)
                return -ENOENT;
+       old_probe_resp = rtnl_dereference(sdata->u.ap.probe_resp);
 
+       /* turn off carrier for this interface and dependent VLANs */
        list_for_each_entry(vlan, &sdata->u.ap.vlans, u.vlan.list)
                netif_carrier_off(vlan->dev);
        netif_carrier_off(dev);
 
+       /* remove beacon and probe response */
        RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
+       RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
+       kfree_rcu(old_beacon, rcu_head);
+       if (old_probe_resp)
+               kfree_rcu(old_probe_resp, rcu_head);
 
-       kfree_rcu(old, rcu_head);
-
-       sta_info_flush(sdata->local, sdata);
+       sta_info_flush(local, sdata);
        ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BEACON_ENABLED);
 
+       drv_stop_ap(sdata->local, sdata);
+
+       /* free all potentially still buffered bcast frames */
+       local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
+       skb_queue_purge(&sdata->u.ap.ps.bc_buf);
+
        ieee80211_vif_release_channel(sdata);
 
        return 0;
@@ -1686,8 +1722,7 @@ static int ieee80211_join_mesh(struct wiphy *wiphy, struct net_device *dev,
        sdata->smps_mode = IEEE80211_SMPS_OFF;
        sdata->needed_rx_chains = sdata->local->rx_chains;
 
-       err = ieee80211_vif_use_channel(sdata, setup->channel,
-                                       setup->channel_type,
+       err = ieee80211_vif_use_channel(sdata, &setup->chandef,
                                        IEEE80211_CHANCTX_SHARED);
        if (err)
                return err;
@@ -1933,6 +1968,16 @@ static int ieee80211_leave_ibss(struct wiphy *wiphy, struct net_device *dev)
        return ieee80211_ibss_leave(IEEE80211_DEV_TO_SUB_IF(dev));
 }
 
+static int ieee80211_set_mcast_rate(struct wiphy *wiphy, struct net_device *dev,
+                                   int rate[IEEE80211_NUM_BANDS])
+{
+       struct ieee80211_sub_if_data *sdata = IEEE80211_DEV_TO_SUB_IF(dev);
+
+       memcpy(sdata->vif.bss_conf.mcast_rate, rate, sizeof(rate));
+
+       return 0;
+}
+
 static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
@@ -1959,10 +2004,16 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
                        return err;
        }
 
-       if (changed & WIPHY_PARAM_RETRY_SHORT)
+       if (changed & WIPHY_PARAM_RETRY_SHORT) {
+               if (wiphy->retry_short > IEEE80211_MAX_TX_RETRY)
+                       return -EINVAL;
                local->hw.conf.short_frame_max_tx_count = wiphy->retry_short;
-       if (changed & WIPHY_PARAM_RETRY_LONG)
+       }
+       if (changed & WIPHY_PARAM_RETRY_LONG) {
+               if (wiphy->retry_long > IEEE80211_MAX_TX_RETRY)
+                       return -EINVAL;
                local->hw.conf.long_frame_max_tx_count = wiphy->retry_long;
+       }
        if (changed &
            (WIPHY_PARAM_RETRY_SHORT | WIPHY_PARAM_RETRY_LONG))
                ieee80211_hw_config(local, IEEE80211_CONF_CHANGE_RETRY_LIMITS);
@@ -1971,45 +2022,65 @@ static int ieee80211_set_wiphy_params(struct wiphy *wiphy, u32 changed)
 }
 
 static int ieee80211_set_tx_power(struct wiphy *wiphy,
+                                 struct wireless_dev *wdev,
                                  enum nl80211_tx_power_setting type, int mbm)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
-       struct ieee80211_channel *chan = local->_oper_channel;
-       u32 changes = 0;
+       struct ieee80211_sub_if_data *sdata;
 
-       /* FIXME */
-       if (local->use_chanctx)
-               return -EOPNOTSUPP;
+       if (wdev) {
+               sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
+
+               switch (type) {
+               case NL80211_TX_POWER_AUTOMATIC:
+                       sdata->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
+                       break;
+               case NL80211_TX_POWER_LIMITED:
+               case NL80211_TX_POWER_FIXED:
+                       if (mbm < 0 || (mbm % 100))
+                               return -EOPNOTSUPP;
+                       sdata->user_power_level = MBM_TO_DBM(mbm);
+                       break;
+               }
+
+               ieee80211_recalc_txpower(sdata);
+
+               return 0;
+       }
 
        switch (type) {
        case NL80211_TX_POWER_AUTOMATIC:
-               local->user_power_level = -1;
+               local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
                break;
        case NL80211_TX_POWER_LIMITED:
-               if (mbm < 0 || (mbm % 100))
-                       return -EOPNOTSUPP;
-               local->user_power_level = MBM_TO_DBM(mbm);
-               break;
        case NL80211_TX_POWER_FIXED:
                if (mbm < 0 || (mbm % 100))
                        return -EOPNOTSUPP;
-               /* TODO: move to cfg80211 when it knows the channel */
-               if (MBM_TO_DBM(mbm) > chan->max_power)
-                       return -EINVAL;
                local->user_power_level = MBM_TO_DBM(mbm);
                break;
        }
 
-       ieee80211_hw_config(local, changes);
+       mutex_lock(&local->iflist_mtx);
+       list_for_each_entry(sdata, &local->interfaces, list)
+               sdata->user_power_level = local->user_power_level;
+       list_for_each_entry(sdata, &local->interfaces, list)
+               ieee80211_recalc_txpower(sdata);
+       mutex_unlock(&local->iflist_mtx);
 
        return 0;
 }
 
-static int ieee80211_get_tx_power(struct wiphy *wiphy, int *dbm)
+static int ieee80211_get_tx_power(struct wiphy *wiphy,
+                                 struct wireless_dev *wdev,
+                                 int *dbm)
 {
        struct ieee80211_local *local = wiphy_priv(wiphy);
+       struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
 
-       *dbm = local->hw.conf.power_level;
+       if (!local->use_chanctx)
+               *dbm = local->hw.conf.power_level;
+       else
+               *dbm = sdata->vif.bss_conf.txpower;
 
        return 0;
 }
@@ -2078,7 +2149,7 @@ int __ieee80211_request_smps(struct ieee80211_sub_if_data *sdata,
         * the new value until we associate.
         */
        if (!sdata->u.mgd.associated ||
-           sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
                return 0;
 
        ap = sdata->u.mgd.associated->bssid;
@@ -2185,7 +2256,6 @@ static int ieee80211_set_bitrate_mask(struct wiphy *wiphy,
 static int ieee80211_start_roc_work(struct ieee80211_local *local,
                                    struct ieee80211_sub_if_data *sdata,
                                    struct ieee80211_channel *channel,
-                                   enum nl80211_channel_type channel_type,
                                    unsigned int duration, u64 *cookie,
                                    struct sk_buff *txskb)
 {
@@ -2203,7 +2273,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                return -ENOMEM;
 
        roc->chan = channel;
-       roc->chan_type = channel_type;
        roc->duration = duration;
        roc->req_duration = duration;
        roc->frame = txskb;
@@ -2236,7 +2305,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
        if (!duration)
                duration = 10;
 
-       ret = drv_remain_on_channel(local, channel, channel_type, duration);
+       ret = drv_remain_on_channel(local, sdata, channel, duration);
        if (ret) {
                kfree(roc);
                return ret;
@@ -2247,7 +2316,7 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
 
  out_check_combine:
        list_for_each_entry(tmp, &local->roc_list, list) {
-               if (tmp->chan != channel || tmp->chan_type != channel_type)
+               if (tmp->chan != channel || tmp->sdata != sdata)
                        continue;
 
                /*
@@ -2341,13 +2410,22 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
                list_add_tail(&roc->list, &local->roc_list);
 
        /*
-        * cookie is either the roc (for normal roc)
+        * cookie is either the roc cookie (for normal roc)
         * or the SKB (for mgmt TX)
         */
-       if (txskb)
+       if (!txskb) {
+               /* local->mtx protects this */
+               local->roc_cookie_counter++;
+               roc->cookie = local->roc_cookie_counter;
+               /* wow, you wrapped 64 bits ... more likely a bug */
+               if (WARN_ON(roc->cookie == 0)) {
+                       roc->cookie = 1;
+                       local->roc_cookie_counter++;
+               }
+               *cookie = roc->cookie;
+       } else {
                *cookie = (unsigned long)txskb;
-       else
-               *cookie = (unsigned long)roc;
+       }
 
        return 0;
 }
@@ -2355,7 +2433,6 @@ static int ieee80211_start_roc_work(struct ieee80211_local *local,
 static int ieee80211_remain_on_channel(struct wiphy *wiphy,
                                       struct wireless_dev *wdev,
                                       struct ieee80211_channel *chan,
-                                      enum nl80211_channel_type channel_type,
                                       unsigned int duration,
                                       u64 *cookie)
 {
@@ -2364,7 +2441,7 @@ static int ieee80211_remain_on_channel(struct wiphy *wiphy,
        int ret;
 
        mutex_lock(&local->mtx);
-       ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+       ret = ieee80211_start_roc_work(local, sdata, chan,
                                       duration, cookie, NULL);
        mutex_unlock(&local->mtx);
 
@@ -2382,7 +2459,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
                struct ieee80211_roc_work *dep, *tmp2;
 
                list_for_each_entry_safe(dep, tmp2, &roc->dependents, list) {
-                       if (!mgmt_tx && (unsigned long)dep != cookie)
+                       if (!mgmt_tx && dep->cookie != cookie)
                                continue;
                        else if (mgmt_tx && dep->mgmt_tx_cookie != cookie)
                                continue;
@@ -2394,7 +2471,7 @@ static int ieee80211_cancel_roc(struct ieee80211_local *local,
                        return 0;
                }
 
-               if (!mgmt_tx && (unsigned long)roc != cookie)
+               if (!mgmt_tx && roc->cookie != cookie)
                        continue;
                else if (mgmt_tx && roc->mgmt_tx_cookie != cookie)
                        continue;
@@ -2457,10 +2534,8 @@ static int ieee80211_cancel_remain_on_channel(struct wiphy *wiphy,
 
 static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                             struct ieee80211_channel *chan, bool offchan,
-                            enum nl80211_channel_type channel_type,
-                            bool channel_type_valid, unsigned int wait,
-                            const u8 *buf, size_t len, bool no_cck,
-                            bool dont_wait_for_ack, u64 *cookie)
+                            unsigned int wait, const u8 *buf, size_t len,
+                            bool no_cck, bool dont_wait_for_ack, u64 *cookie)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
        struct ieee80211_local *local = sdata->local;
@@ -2529,14 +2604,10 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                rcu_read_lock();
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 
-               if (chanctx_conf) {
-                       need_offchan = chan != chanctx_conf->channel;
-                       if (channel_type_valid &&
-                           channel_type != chanctx_conf->channel_type)
-                               need_offchan = true;
-               } else {
+               if (chanctx_conf)
+                       need_offchan = chan != chanctx_conf->def.chan;
+               else
                        need_offchan = true;
-               }
                rcu_read_unlock();
        }
 
@@ -2571,7 +2642,7 @@ static int ieee80211_mgmt_tx(struct wiphy *wiphy, struct wireless_dev *wdev,
                        local->hw.offchannel_tx_hw_queue;
 
        /* This will handle all kinds of coalescing and immediate TX */
-       ret = ieee80211_start_roc_work(local, sdata, chan, channel_type,
+       ret = ieee80211_start_roc_work(local, sdata, chan,
                                       wait, cookie, skb);
        if (ret)
                kfree_skb(skb);
@@ -3005,7 +3076,7 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
                rcu_read_unlock();
                return -EINVAL;
        }
-       band = chanctx_conf->channel->band;
+       band = chanctx_conf->def.chan->band;
        sta = sta_info_get(sdata, peer);
        if (sta) {
                qos = test_sta_flag(sta, WLAN_STA_WME);
@@ -3062,23 +3133,23 @@ static int ieee80211_probe_client(struct wiphy *wiphy, struct net_device *dev,
        return 0;
 }
 
-static struct ieee80211_channel *
-ieee80211_cfg_get_channel(struct wiphy *wiphy, struct wireless_dev *wdev,
-                         enum nl80211_channel_type *type)
+static int ieee80211_cfg_get_channel(struct wiphy *wiphy,
+                                    struct wireless_dev *wdev,
+                                    struct cfg80211_chan_def *chandef)
 {
        struct ieee80211_sub_if_data *sdata = IEEE80211_WDEV_TO_SUB_IF(wdev);
        struct ieee80211_chanctx_conf *chanctx_conf;
-       struct ieee80211_channel *chan = NULL;
+       int ret = -ENODATA;
 
        rcu_read_lock();
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (chanctx_conf) {
-               *type = chanctx_conf->channel_type;
-               chan = chanctx_conf->channel;
+               *chandef = chanctx_conf->def;
+               ret = 0;
        }
        rcu_read_unlock();
 
-       return chan;
+       return ret;
 }
 
 #ifdef CONFIG_PM
@@ -3133,6 +3204,7 @@ struct cfg80211_ops mac80211_config_ops = {
        .disassoc = ieee80211_disassoc,
        .join_ibss = ieee80211_join_ibss,
        .leave_ibss = ieee80211_leave_ibss,
+       .set_mcast_rate = ieee80211_set_mcast_rate,
        .set_wiphy_params = ieee80211_set_wiphy_params,
        .set_tx_power = ieee80211_set_tx_power,
        .get_tx_power = ieee80211_get_tx_power,
index f84b86028a9cd50bc95c10ec3410c4250c190eb1..53f03120db55dc3d2c1e8c775a054182d21dac69 100644 (file)
@@ -8,93 +8,47 @@
 #include "ieee80211_i.h"
 #include "driver-ops.h"
 
-static bool
-ieee80211_channel_types_are_compatible(enum nl80211_channel_type chantype1,
-                                      enum nl80211_channel_type chantype2,
-                                      enum nl80211_channel_type *compat)
+static void ieee80211_change_chandef(struct ieee80211_local *local,
+                                    struct ieee80211_chanctx *ctx,
+                                    const struct cfg80211_chan_def *chandef)
 {
-       /*
-        * start out with chantype1 being the result,
-        * overwriting later if needed
-        */
-       if (compat)
-               *compat = chantype1;
-
-       switch (chantype1) {
-       case NL80211_CHAN_NO_HT:
-               if (compat)
-                       *compat = chantype2;
-               break;
-       case NL80211_CHAN_HT20:
-               /*
-                * allow any change that doesn't go to no-HT
-                * (if it already is no-HT no change is needed)
-                */
-               if (chantype2 == NL80211_CHAN_NO_HT)
-                       break;
-               if (compat)
-                       *compat = chantype2;
-               break;
-       case NL80211_CHAN_HT40PLUS:
-       case NL80211_CHAN_HT40MINUS:
-               /* allow smaller bandwidth and same */
-               if (chantype2 == NL80211_CHAN_NO_HT)
-                       break;
-               if (chantype2 == NL80211_CHAN_HT20)
-                       break;
-               if (chantype2 == chantype1)
-                       break;
-               return false;
-       }
-
-       return true;
-}
-
-static void ieee80211_change_chantype(struct ieee80211_local *local,
-                                     struct ieee80211_chanctx *ctx,
-                                     enum nl80211_channel_type chantype)
-{
-       if (chantype == ctx->conf.channel_type)
+       if (cfg80211_chandef_identical(&ctx->conf.def, chandef))
                return;
 
-       ctx->conf.channel_type = chantype;
-       drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_CHANNEL_TYPE);
+       WARN_ON(!cfg80211_chandef_compatible(&ctx->conf.def, chandef));
+
+       ctx->conf.def = *chandef;
+       drv_change_chanctx(local, ctx, IEEE80211_CHANCTX_CHANGE_WIDTH);
 
        if (!local->use_chanctx) {
-               local->_oper_channel_type = chantype;
+               local->_oper_channel_type = cfg80211_get_chandef_type(chandef);
                ieee80211_hw_config(local, 0);
        }
 }
 
 static struct ieee80211_chanctx *
 ieee80211_find_chanctx(struct ieee80211_local *local,
-                      struct ieee80211_channel *channel,
-                      enum nl80211_channel_type channel_type,
+                      const struct cfg80211_chan_def *chandef,
                       enum ieee80211_chanctx_mode mode)
 {
        struct ieee80211_chanctx *ctx;
-       enum nl80211_channel_type compat_type;
 
        lockdep_assert_held(&local->chanctx_mtx);
 
        if (mode == IEEE80211_CHANCTX_EXCLUSIVE)
                return NULL;
-       if (WARN_ON(!channel))
-               return NULL;
 
        list_for_each_entry(ctx, &local->chanctx_list, list) {
-               compat_type = ctx->conf.channel_type;
+               const struct cfg80211_chan_def *compat;
 
                if (ctx->mode == IEEE80211_CHANCTX_EXCLUSIVE)
                        continue;
-               if (ctx->conf.channel != channel)
-                       continue;
-               if (!ieee80211_channel_types_are_compatible(ctx->conf.channel_type,
-                                                           channel_type,
-                                                           &compat_type))
+
+               compat = cfg80211_chandef_compatible(&ctx->conf.def, chandef);
+               if (!compat)
                        continue;
 
-               ieee80211_change_chantype(local, ctx, compat_type);
+               ieee80211_change_chandef(local, ctx, compat);
 
                return ctx;
        }
@@ -104,8 +58,7 @@ ieee80211_find_chanctx(struct ieee80211_local *local,
 
 static struct ieee80211_chanctx *
 ieee80211_new_chanctx(struct ieee80211_local *local,
-                     struct ieee80211_channel *channel,
-                     enum nl80211_channel_type channel_type,
+                     const struct cfg80211_chan_def *chandef,
                      enum ieee80211_chanctx_mode mode)
 {
        struct ieee80211_chanctx *ctx;
@@ -117,15 +70,15 @@ ieee80211_new_chanctx(struct ieee80211_local *local,
        if (!ctx)
                return ERR_PTR(-ENOMEM);
 
-       ctx->conf.channel = channel;
-       ctx->conf.channel_type = channel_type;
+       ctx->conf.def = *chandef;
        ctx->conf.rx_chains_static = 1;
        ctx->conf.rx_chains_dynamic = 1;
        ctx->mode = mode;
 
        if (!local->use_chanctx) {
-               local->_oper_channel_type = channel_type;
-               local->_oper_channel = channel;
+               local->_oper_channel_type =
+                       cfg80211_get_chandef_type(chandef);
+               local->_oper_channel = chandef->chan;
                ieee80211_hw_config(local, 0);
        } else {
                err = drv_add_chanctx(local, ctx);
@@ -173,44 +126,42 @@ static int ieee80211_assign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
        rcu_assign_pointer(sdata->vif.chanctx_conf, &ctx->conf);
        ctx->refcount++;
 
+       ieee80211_recalc_txpower(sdata);
+
        return 0;
 }
 
-static enum nl80211_channel_type
-ieee80211_calc_chantype(struct ieee80211_local *local,
-                       struct ieee80211_chanctx *ctx)
+static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
+                                             struct ieee80211_chanctx *ctx)
 {
        struct ieee80211_chanctx_conf *conf = &ctx->conf;
        struct ieee80211_sub_if_data *sdata;
-       enum nl80211_channel_type result = NL80211_CHAN_NO_HT;
+       const struct cfg80211_chan_def *compat = NULL;
 
        lockdep_assert_held(&local->chanctx_mtx);
 
        rcu_read_lock();
        list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+
                if (!ieee80211_sdata_running(sdata))
                        continue;
                if (rcu_access_pointer(sdata->vif.chanctx_conf) != conf)
                        continue;
 
-               WARN_ON_ONCE(!ieee80211_channel_types_are_compatible(
-                                       sdata->vif.bss_conf.channel_type,
-                                       result, &result));
+               if (!compat)
+                       compat = &sdata->vif.bss_conf.chandef;
+
+               compat = cfg80211_chandef_compatible(
+                               &sdata->vif.bss_conf.chandef, compat);
+               if (!compat)
+                       break;
        }
        rcu_read_unlock();
 
-       return result;
-}
-
-static void ieee80211_recalc_chanctx_chantype(struct ieee80211_local *local,
-                                             struct ieee80211_chanctx *ctx)
-{
-       enum nl80211_channel_type chantype;
-
-       lockdep_assert_held(&local->chanctx_mtx);
+       if (WARN_ON_ONCE(!compat))
+               return;
 
-       chantype = ieee80211_calc_chantype(local, ctx);
-       ieee80211_change_chantype(local, ctx, chantype);
+       ieee80211_change_chandef(local, ctx, compat);
 }
 
 static void ieee80211_unassign_vif_chanctx(struct ieee80211_sub_if_data *sdata,
@@ -335,8 +286,7 @@ void ieee80211_recalc_smps_chanctx(struct ieee80211_local *local,
 }
 
 int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
-                             struct ieee80211_channel *channel,
-                             enum nl80211_channel_type channel_type,
+                             const struct cfg80211_chan_def *chandef,
                              enum ieee80211_chanctx_mode mode)
 {
        struct ieee80211_local *local = sdata->local;
@@ -348,15 +298,15 @@ int ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
        mutex_lock(&local->chanctx_mtx);
        __ieee80211_vif_release_channel(sdata);
 
-       ctx = ieee80211_find_chanctx(local, channel, channel_type, mode);
+       ctx = ieee80211_find_chanctx(local, chandef, mode);
        if (!ctx)
-               ctx = ieee80211_new_chanctx(local, channel, channel_type, mode);
+               ctx = ieee80211_new_chanctx(local, chandef, mode);
        if (IS_ERR(ctx)) {
                ret = PTR_ERR(ctx);
                goto out;
        }
 
-       sdata->vif.bss_conf.channel_type = channel_type;
+       sdata->vif.bss_conf.chandef = *chandef;
 
        ret = ieee80211_assign_vif_chanctx(sdata, ctx);
        if (ret) {
index 090d08ff22c4b753972959c520e87254feb4281d..2d4235497f1be90e6a8f59229368c34716563aaf 100644 (file)
@@ -116,7 +116,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
                                size_t count, loff_t *ppos)
 {
        struct ieee80211_key *key = file->private_data;
-       char buf[14*NUM_RX_DATA_QUEUES+1], *p = buf;
+       char buf[14*IEEE80211_NUM_TIDS+1], *p = buf;
        int i, len;
        const u8 *rpn;
 
@@ -126,7 +126,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
                len = scnprintf(buf, sizeof(buf), "\n");
                break;
        case WLAN_CIPHER_SUITE_TKIP:
-               for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+               for (i = 0; i < IEEE80211_NUM_TIDS; i++)
                        p += scnprintf(p, sizeof(buf)+buf-p,
                                       "%08x %04x\n",
                                       key->u.tkip.rx[i].iv32,
@@ -134,7 +134,7 @@ static ssize_t key_rx_spec_read(struct file *file, char __user *userbuf,
                len = p - buf;
                break;
        case WLAN_CIPHER_SUITE_CCMP:
-               for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++) {
+               for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++) {
                        rpn = key->u.ccmp.rx_pn[i];
                        p += scnprintf(p, sizeof(buf)+buf-p,
                                       "%02x%02x%02x%02x%02x%02x\n",
index 3393ad5b8ab1875c5252bfe921b6e3c28680a524..cbde5cc49a4041fa338f74017c2ad72384fb0ff2 100644 (file)
@@ -10,6 +10,7 @@
 #include <linux/kernel.h>
 #include <linux/device.h>
 #include <linux/if.h>
+#include <linux/if_ether.h>
 #include <linux/interrupt.h>
 #include <linux/netdevice.h>
 #include <linux/rtnetlink.h>
@@ -167,7 +168,29 @@ IEEE80211_IF_FILE(rc_rateidx_mcs_mask_5ghz,
 
 IEEE80211_IF_FILE(flags, flags, HEX);
 IEEE80211_IF_FILE(state, state, LHEX);
-IEEE80211_IF_FILE(channel_type, vif.bss_conf.channel_type, DEC);
+IEEE80211_IF_FILE(txpower, vif.bss_conf.txpower, DEC);
+IEEE80211_IF_FILE(ap_power_level, ap_power_level, DEC);
+IEEE80211_IF_FILE(user_power_level, user_power_level, DEC);
+
+static ssize_t
+ieee80211_if_fmt_hw_queues(const struct ieee80211_sub_if_data *sdata,
+                          char *buf, int buflen)
+{
+       int len;
+
+       len = scnprintf(buf, buflen, "AC queues: VO:%d VI:%d BE:%d BK:%d\n",
+                       sdata->vif.hw_queue[IEEE80211_AC_VO],
+                       sdata->vif.hw_queue[IEEE80211_AC_VI],
+                       sdata->vif.hw_queue[IEEE80211_AC_BE],
+                       sdata->vif.hw_queue[IEEE80211_AC_BK]);
+
+       if (sdata->vif.type == NL80211_IFTYPE_AP)
+               len += scnprintf(buf + len, buflen - len, "cab queue: %d\n",
+                                sdata->vif.cab_queue);
+
+       return len;
+}
+__IEEE80211_IF_FILE(hw_queues, NULL);
 
 /* STA attributes */
 IEEE80211_IF_FILE(bssid, u.mgd.bssid, MAC);
@@ -245,27 +268,6 @@ static ssize_t ieee80211_if_fmt_tkip_mic_test(
        return -EOPNOTSUPP;
 }
 
-static int hwaddr_aton(const char *txt, u8 *addr)
-{
-       int i;
-
-       for (i = 0; i < ETH_ALEN; i++) {
-               int a, b;
-
-               a = hex_to_bin(*txt++);
-               if (a < 0)
-                       return -1;
-               b = hex_to_bin(*txt++);
-               if (b < 0)
-                       return -1;
-               *addr++ = (a << 4) | b;
-               if (i < 5 && *txt++ != ':')
-                       return -1;
-       }
-
-       return 0;
-}
-
 static ssize_t ieee80211_if_parse_tkip_mic_test(
        struct ieee80211_sub_if_data *sdata, const char *buf, int buflen)
 {
@@ -275,13 +277,7 @@ static ssize_t ieee80211_if_parse_tkip_mic_test(
        struct ieee80211_hdr *hdr;
        __le16 fc;
 
-       /*
-        * Assume colon-delimited MAC address with possible white space
-        * following.
-        */
-       if (buflen < 3 * ETH_ALEN - 1)
-               return -EINVAL;
-       if (hwaddr_aton(buf, addr) < 0)
+       if (!mac_pton(buf, addr))
                return -EINVAL;
 
        if (!ieee80211_sdata_running(sdata))
@@ -307,13 +303,16 @@ static ssize_t ieee80211_if_parse_tkip_mic_test(
        case NL80211_IFTYPE_STATION:
                fc |= cpu_to_le16(IEEE80211_FCTL_TODS);
                /* BSSID SA DA */
-               if (sdata->vif.bss_conf.bssid == NULL) {
+               mutex_lock(&sdata->u.mgd.mtx);
+               if (!sdata->u.mgd.associated) {
+                       mutex_unlock(&sdata->u.mgd.mtx);
                        dev_kfree_skb(skb);
                        return -ENOTCONN;
                }
-               memcpy(hdr->addr1, sdata->vif.bss_conf.bssid, ETH_ALEN);
+               memcpy(hdr->addr1, sdata->u.mgd.associated->bssid, ETH_ALEN);
                memcpy(hdr->addr2, sdata->vif.addr, ETH_ALEN);
                memcpy(hdr->addr3, addr, ETH_ALEN);
+               mutex_unlock(&sdata->u.mgd.mtx);
                break;
        default:
                dev_kfree_skb(skb);
@@ -443,7 +442,7 @@ static ssize_t ieee80211_if_parse_tsf(
                }
                ret = kstrtoull(buf, 10, &tsf);
                if (ret < 0)
-                       return -EINVAL;
+                       return ret;
                if (tsf_is_delta)
                        tsf = drv_get_tsf(local, sdata) + tsf_is_delta * tsf;
                if (local->ops->set_tsf) {
@@ -531,6 +530,7 @@ static void add_common_files(struct ieee80211_sub_if_data *sdata)
        DEBUGFS_ADD(rc_rateidx_mask_5ghz);
        DEBUGFS_ADD(rc_rateidx_mcs_mask_2ghz);
        DEBUGFS_ADD(rc_rateidx_mcs_mask_5ghz);
+       DEBUGFS_ADD(hw_queues);
 }
 
 static void add_sta_files(struct ieee80211_sub_if_data *sdata)
@@ -631,7 +631,9 @@ static void add_files(struct ieee80211_sub_if_data *sdata)
 
        DEBUGFS_ADD(flags);
        DEBUGFS_ADD(state);
-       DEBUGFS_ADD(channel_type);
+       DEBUGFS_ADD(txpower);
+       DEBUGFS_ADD(user_power_level);
+       DEBUGFS_ADD(ap_power_level);
 
        if (sdata->vif.type != NL80211_IFTYPE_MONITOR)
                add_common_files(sdata);
index 5ccec2c1e9f669165763372176e62fbc2562d049..89281d24b0943a41f68ab4d7e3def0e74ffc6d40 100644 (file)
@@ -14,6 +14,7 @@
 #include "debugfs.h"
 #include "debugfs_sta.h"
 #include "sta_info.h"
+#include "driver-ops.h"
 
 /* sta attributtes */
 
@@ -131,10 +132,10 @@ STA_OPS(connected_time);
 static ssize_t sta_last_seq_ctrl_read(struct file *file, char __user *userbuf,
                                      size_t count, loff_t *ppos)
 {
-       char buf[15*NUM_RX_DATA_QUEUES], *p = buf;
+       char buf[15*IEEE80211_NUM_TIDS], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
-       for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++)
                p += scnprintf(p, sizeof(buf)+buf-p, "%x ",
                               le16_to_cpu(sta->last_seq_ctrl[i]));
        p += scnprintf(p, sizeof(buf)+buf-p, "\n");
@@ -145,7 +146,7 @@ STA_OPS(last_seq_ctrl);
 static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
                                        size_t count, loff_t *ppos)
 {
-       char buf[71 + STA_TID_NUM * 40], *p = buf;
+       char buf[71 + IEEE80211_NUM_TIDS * 40], *p = buf;
        int i;
        struct sta_info *sta = file->private_data;
        struct tid_ampdu_rx *tid_rx;
@@ -158,7 +159,7 @@ static ssize_t sta_agg_status_read(struct file *file, char __user *userbuf,
        p += scnprintf(p, sizeof(buf) + buf - p,
                       "TID\t\tRX active\tDTKN\tSSN\t\tTX\tDTKN\tpending\n");
 
-       for (i = 0; i < STA_TID_NUM; i++) {
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
                tid_rx = rcu_dereference(sta->ampdu_mlme.tid_rx[i]);
                tid_tx = rcu_dereference(sta->ampdu_mlme.tid_tx[i]);
 
@@ -220,7 +221,7 @@ static ssize_t sta_agg_status_write(struct file *file, const char __user *userbu
 
        tid = simple_strtoul(buf, NULL, 0);
 
-       if (tid >= STA_TID_NUM)
+       if (tid >= IEEE80211_NUM_TIDS)
                return -EINVAL;
 
        if (tx) {
@@ -334,6 +335,8 @@ STA_OPS(ht_capa);
 
 void ieee80211_sta_debugfs_add(struct sta_info *sta)
 {
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
        struct dentry *stations_dir = sta->sdata->debugfs.subdir_stations;
        u8 mac[3*ETH_ALEN];
 
@@ -379,10 +382,16 @@ void ieee80211_sta_debugfs_add(struct sta_info *sta)
        DEBUGFS_ADD_COUNTER(tx_retry_failed, tx_retry_failed);
        DEBUGFS_ADD_COUNTER(tx_retry_count, tx_retry_count);
        DEBUGFS_ADD_COUNTER(wep_weak_iv_count, wep_weak_iv_count);
+
+       drv_sta_add_debugfs(local, sdata, &sta->sta, sta->debugfs.dir);
 }
 
 void ieee80211_sta_debugfs_remove(struct sta_info *sta)
 {
+       struct ieee80211_local *local = sta->local;
+       struct ieee80211_sub_if_data *sdata = sta->sdata;
+
+       drv_sta_remove_debugfs(local, sdata, &sta->sta, sta->debugfs.dir);
        debugfs_remove_recursive(sta->debugfs.dir);
        sta->debugfs.dir = NULL;
 }
index 77407b31e1ffb7120927f872f24ce5276904c5fe..c6560cc7a9d6468b6b3239afc81baaecccc3957e 100644 (file)
@@ -490,6 +490,38 @@ static inline void drv_sta_remove(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
+#ifdef CONFIG_MAC80211_DEBUGFS
+static inline void drv_sta_add_debugfs(struct ieee80211_local *local,
+                                      struct ieee80211_sub_if_data *sdata,
+                                      struct ieee80211_sta *sta,
+                                      struct dentry *dir)
+{
+       might_sleep();
+
+       sdata = get_bss_sdata(sdata);
+       check_sdata_in_driver(sdata);
+
+       if (local->ops->sta_add_debugfs)
+               local->ops->sta_add_debugfs(&local->hw, &sdata->vif,
+                                           sta, dir);
+}
+
+static inline void drv_sta_remove_debugfs(struct ieee80211_local *local,
+                                         struct ieee80211_sub_if_data *sdata,
+                                         struct ieee80211_sta *sta,
+                                         struct dentry *dir)
+{
+       might_sleep();
+
+       sdata = get_bss_sdata(sdata);
+       check_sdata_in_driver(sdata);
+
+       if (local->ops->sta_remove_debugfs)
+               local->ops->sta_remove_debugfs(&local->hw, &sdata->vif,
+                                              sta, dir);
+}
+#endif
+
 static inline __must_check
 int drv_sta_state(struct ieee80211_local *local,
                  struct ieee80211_sub_if_data *sdata,
@@ -704,17 +736,17 @@ static inline int drv_get_antenna(struct ieee80211_local *local,
 }
 
 static inline int drv_remain_on_channel(struct ieee80211_local *local,
+                                       struct ieee80211_sub_if_data *sdata,
                                        struct ieee80211_channel *chan,
-                                       enum nl80211_channel_type chantype,
                                        unsigned int duration)
 {
        int ret;
 
        might_sleep();
 
-       trace_drv_remain_on_channel(local, chan, chantype, duration);
-       ret = local->ops->remain_on_channel(&local->hw, chan, chantype,
-                                           duration);
+       trace_drv_remain_on_channel(local, sdata, chan, duration);
+       ret = local->ops->remain_on_channel(&local->hw, &sdata->vif,
+                                           chan, duration);
        trace_drv_return_int(local, ret);
 
        return ret;
@@ -936,4 +968,39 @@ static inline void drv_unassign_vif_chanctx(struct ieee80211_local *local,
        trace_drv_return_void(local);
 }
 
+static inline int drv_start_ap(struct ieee80211_local *local,
+                              struct ieee80211_sub_if_data *sdata)
+{
+       int ret = 0;
+
+       check_sdata_in_driver(sdata);
+
+       trace_drv_start_ap(local, sdata, &sdata->vif.bss_conf);
+       if (local->ops->start_ap)
+               ret = local->ops->start_ap(&local->hw, &sdata->vif);
+       trace_drv_return_int(local, ret);
+       return ret;
+}
+
+static inline void drv_stop_ap(struct ieee80211_local *local,
+                              struct ieee80211_sub_if_data *sdata)
+{
+       check_sdata_in_driver(sdata);
+
+       trace_drv_stop_ap(local, sdata);
+       if (local->ops->stop_ap)
+               local->ops->stop_ap(&local->hw, &sdata->vif);
+       trace_drv_return_void(local);
+}
+
+static inline void drv_restart_complete(struct ieee80211_local *local)
+{
+       might_sleep();
+
+       trace_drv_restart_complete(local);
+       if (local->ops->restart_complete)
+               local->ops->restart_complete(&local->hw);
+       trace_drv_return_void(local);
+}
+
 #endif /* __MAC80211_DRIVER_OPS */
index 4b4538d6392589897154035f6ab6305e2d3ebb28..a71d891794a40ab96134ec16eef5568e8b5b3eca 100644 (file)
@@ -185,7 +185,7 @@ void ieee80211_sta_tear_down_BA_sessions(struct sta_info *sta, bool tx)
 
        cancel_work_sync(&sta->ampdu_mlme.work);
 
-       for (i = 0; i <  STA_TID_NUM; i++) {
+       for (i = 0; i <  IEEE80211_NUM_TIDS; i++) {
                __ieee80211_stop_tx_ba_session(sta, i, WLAN_BACK_INITIATOR, tx);
                __ieee80211_stop_rx_ba_session(sta, i, WLAN_BACK_RECIPIENT,
                                               WLAN_REASON_QSTA_LEAVE_QBSS, tx);
@@ -209,7 +209,7 @@ void ieee80211_ba_session_work(struct work_struct *work)
                return;
 
        mutex_lock(&sta->ampdu_mlme.mtx);
-       for (tid = 0; tid < STA_TID_NUM; tid++) {
+       for (tid = 0; tid < IEEE80211_NUM_TIDS; tid++) {
                if (test_and_clear_bit(tid, sta->ampdu_mlme.tid_rx_timer_expired))
                        ___ieee80211_stop_rx_ba_session(
                                sta, tid, WLAN_BACK_RECIPIENT,
index 67774b053535c2f50696d5274baba2b0efa6c919..fa862b24a7e017a946a4f9260a62651117c25b3e 100644 (file)
@@ -51,7 +51,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
        struct cfg80211_bss *bss;
        u32 bss_change;
        u8 supp_rates[IEEE80211_MAX_SUPP_RATES];
-       enum nl80211_channel_type channel_type;
+       struct cfg80211_chan_def chandef;
 
        lockdep_assert_held(&ifibss->mtx);
 
@@ -79,12 +79,14 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
 
        sdata->drop_unencrypted = capability & WLAN_CAPABILITY_PRIVACY ? 1 : 0;
 
-       channel_type = ifibss->channel_type;
-       if (!cfg80211_can_beacon_sec_chan(local->hw.wiphy, chan, channel_type))
-               channel_type = NL80211_CHAN_HT20;
+       cfg80211_chandef_create(&chandef, chan, ifibss->channel_type);
+       if (!cfg80211_reg_can_beacon(local->hw.wiphy, &chandef)) {
+               chandef.width = NL80211_CHAN_WIDTH_20;
+               chandef.center_freq1 = chan->center_freq;
+       }
 
        ieee80211_vif_release_channel(sdata);
-       if (ieee80211_vif_use_channel(sdata, chan, channel_type,
+       if (ieee80211_vif_use_channel(sdata, &chandef,
                                      ifibss->fixed_channel ?
                                        IEEE80211_CHANCTX_SHARED :
                                        IEEE80211_CHANCTX_EXCLUSIVE)) {
@@ -158,7 +160,8 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                       ifibss->ie, ifibss->ie_len);
 
        /* add HT capability and information IEs */
-       if (channel_type && sband->ht_cap.ht_supported) {
+       if (chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
+           sband->ht_cap.ht_supported) {
                pos = skb_put(skb, 4 +
                                   sizeof(struct ieee80211_ht_cap) +
                                   sizeof(struct ieee80211_ht_operation));
@@ -170,7 +173,7 @@ static void __ieee80211_sta_join_ibss(struct ieee80211_sub_if_data *sdata,
                 * keep them at 0
                 */
                pos = ieee80211_ie_build_ht_oper(pos, &sband->ht_cap,
-                                                chan, channel_type, 0);
+                                                &chandef, 0);
        }
 
        if (local->hw.queues >= IEEE80211_NUM_ACS) {
@@ -326,7 +329,7 @@ ieee80211_ibss_add_sta(struct ieee80211_sub_if_data *sdata,
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (WARN_ON_ONCE(!chanctx_conf))
                return NULL;
-       band = chanctx_conf->channel->band;
+       band = chanctx_conf->def.chan->band;
        rcu_read_unlock();
 
        sta = sta_info_alloc(sdata, addr, GFP_KERNEL);
@@ -374,11 +377,13 @@ static void ieee80211_rx_mgmt_auth_ibss(struct ieee80211_sub_if_data *sdata,
        auth_alg = le16_to_cpu(mgmt->u.auth.auth_alg);
        auth_transaction = le16_to_cpu(mgmt->u.auth.auth_transaction);
 
-       if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
-               return;
        ibss_dbg(sdata,
                 "RX Auth SA=%pM DA=%pM BSSID=%pM (auth_transaction=%d)\n",
                 mgmt->sa, mgmt->da, mgmt->bssid, auth_transaction);
+
+       if (auth_alg != WLAN_AUTH_OPEN || auth_transaction != 1)
+               return;
+
        sta_info_destroy_addr(sdata, mgmt->sa);
        sta = ieee80211_ibss_add_sta(sdata, mgmt->bssid, mgmt->sa, 0, false);
        rcu_read_unlock();
@@ -473,9 +478,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                    sdata->u.ibss.channel_type != NL80211_CHAN_NO_HT) {
                        /* we both use HT */
                        struct ieee80211_sta_ht_cap sta_ht_cap_new;
-                       enum nl80211_channel_type channel_type =
-                               ieee80211_ht_oper_to_channel_type(
-                                                       elems->ht_operation);
+                       struct cfg80211_chan_def chandef;
+
+                       ieee80211_ht_oper_to_chandef(channel,
+                                                    elems->ht_operation,
+                                                    &chandef);
 
                        ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                                          elems->ht_cap_elem,
@@ -485,9 +492,9 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
                         * fall back to HT20 if we don't use or use
                         * the other extension channel
                         */
-                       if (!(channel_type == NL80211_CHAN_HT40MINUS ||
-                             channel_type == NL80211_CHAN_HT40PLUS) ||
-                           channel_type != sdata->u.ibss.channel_type)
+                       if (chandef.width != NL80211_CHAN_WIDTH_40 ||
+                           cfg80211_get_chandef_type(&chandef) !=
+                                               sdata->u.ibss.channel_type)
                                sta_ht_cap_new.cap &=
                                        ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
 
@@ -543,30 +550,11 @@ static void ieee80211_rx_bss_info(struct ieee80211_sub_if_data *sdata,
        if (ether_addr_equal(cbss->bssid, sdata->u.ibss.bssid))
                goto put_bss;
 
-       if (rx_status->flag & RX_FLAG_MACTIME_MPDU) {
-               /*
-                * For correct IBSS merging we need mactime; since mactime is
-                * defined as the time the first data symbol of the frame hits
-                * the PHY, and the timestamp of the beacon is defined as "the
-                * time that the data symbol containing the first bit of the
-                * timestamp is transmitted to the PHY plus the transmitting
-                * STA's delays through its local PHY from the MAC-PHY
-                * interface to its interface with the WM" (802.11 11.1.2)
-                * - equals the time this bit arrives at the receiver - we have
-                * to take into account the offset between the two.
-                *
-                * E.g. at 1 MBit that means mactime is 192 usec earlier
-                * (=24 bytes * 8 usecs/byte) than the beacon timestamp.
-                */
-               int rate;
-
-               if (rx_status->flag & RX_FLAG_HT)
-                       rate = 65; /* TODO: HT rates */
-               else
-                       rate = local->hw.wiphy->bands[band]->
-                               bitrates[rx_status->rate_idx].bitrate;
-
-               rx_timestamp = rx_status->mactime + (24 * 8 * 10 / rate);
+       if (ieee80211_have_rx_timestamp(rx_status)) {
+               /* time when timestamp field was received */
+               rx_timestamp =
+                       ieee80211_calculate_rx_timestamp(local, rx_status,
+                                                        len + FCS_LEN, 24);
        } else {
                /*
                 * second best option: get current TSF
@@ -630,7 +618,7 @@ void ieee80211_ibss_rx_no_sta(struct ieee80211_sub_if_data *sdata,
                rcu_read_unlock();
                return;
        }
-       band = chanctx_conf->channel->band;
+       band = chanctx_conf->def.chan->band;
        rcu_read_unlock();
 
        sta = sta_info_alloc(sdata, addr, GFP_ATOMIC);
@@ -1095,8 +1083,9 @@ int ieee80211_ibss_join(struct ieee80211_sub_if_data *sdata,
 
        sdata->vif.bss_conf.beacon_int = params->beacon_interval;
 
-       sdata->u.ibss.channel = params->channel;
-       sdata->u.ibss.channel_type = params->channel_type;
+       sdata->u.ibss.channel = params->chandef.chan;
+       sdata->u.ibss.channel_type =
+               cfg80211_get_chandef_type(&params->chandef);
        sdata->u.ibss.fixed_channel = params->channel_fixed;
 
        if (params->ie) {
index 32e47853f329262eb46fbd57a81e492a1354d4bd..5c0d5a6946c13b459b08b97f99affa16af0caded 100644 (file)
@@ -56,6 +56,9 @@ struct ieee80211_local;
 #define TU_TO_JIFFIES(x)       (usecs_to_jiffies((x) * 1024))
 #define TU_TO_EXP_TIME(x)      (jiffies + TU_TO_JIFFIES(x))
 
+/* power level hasn't been configured (or set to automatic) */
+#define IEEE80211_UNSET_POWER_LEVEL    INT_MIN
+
 /*
  * Some APs experience problems when working with U-APSD. Decrease the
  * probability of that happening by using legacy mode for all ACs but VO.
@@ -345,7 +348,6 @@ struct ieee80211_roc_work {
        struct ieee80211_sub_if_data *sdata;
 
        struct ieee80211_channel *chan;
-       enum nl80211_channel_type chan_type;
 
        bool started, abort, hw_begun, notified;
 
@@ -353,7 +355,7 @@ struct ieee80211_roc_work {
 
        u32 duration, req_duration;
        struct sk_buff *frame;
-       u64 mgmt_tx_cookie;
+       u64 cookie, mgmt_tx_cookie;
 };
 
 /* flags used in struct ieee80211_if_managed.flags */
@@ -361,7 +363,7 @@ enum ieee80211_sta_flags {
        IEEE80211_STA_BEACON_POLL       = BIT(0),
        IEEE80211_STA_CONNECTION_POLL   = BIT(1),
        IEEE80211_STA_CONTROL_PORT      = BIT(2),
-       IEEE80211_STA_DISABLE_11N       = BIT(4),
+       IEEE80211_STA_DISABLE_HT        = BIT(4),
        IEEE80211_STA_CSA_RECEIVED      = BIT(5),
        IEEE80211_STA_MFP_ENABLED       = BIT(6),
        IEEE80211_STA_UAPSD_ENABLED     = BIT(7),
@@ -470,6 +472,8 @@ struct ieee80211_if_managed {
 
        u8 use_4addr;
 
+       u8 p2p_noa_index;
+
        /* Signal strength from the last Beacon frame in the current BSS. */
        int last_beacon_signal;
 
@@ -743,6 +747,9 @@ struct ieee80211_sub_if_data {
        u8 needed_rx_chains;
        enum ieee80211_smps_mode smps_mode;
 
+       int user_power_level; /* in dBm */
+       int ap_power_level; /* in dBm */
+
        /*
         * AP this belongs to: self in AP mode and
         * corresponding AP in VLAN mode, NULL for
@@ -792,7 +799,7 @@ ieee80211_get_sdata_band(struct ieee80211_sub_if_data *sdata)
        rcu_read_lock();
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        if (!WARN_ON(!chanctx_conf))
-               band = chanctx_conf->channel->band;
+               band = chanctx_conf->def.chan->band;
        rcu_read_unlock();
 
        return band;
@@ -1040,7 +1047,6 @@ struct ieee80211_local {
 
        /* Temporary remain-on-channel for off-channel operations */
        struct ieee80211_channel *tmp_channel;
-       enum nl80211_channel_type tmp_channel_type;
 
        /* channel contexts */
        struct list_head chanctx_list;
@@ -1117,8 +1123,7 @@ struct ieee80211_local {
        int dynamic_ps_user_timeout;
        bool disable_dynamic_ps;
 
-       int user_power_level; /* in dBm */
-       int ap_power_level; /* in dBm */
+       int user_power_level; /* in dBm, for all interfaces */
 
        enum ieee80211_smps_mode smps_mode;
 
@@ -1137,6 +1142,7 @@ struct ieee80211_local {
        struct list_head roc_list;
        struct work_struct hw_roc_start, hw_roc_done;
        unsigned long hw_roc_start_time;
+       u64 roc_cookie_counter;
 
        struct idr ack_status_frames;
        spinlock_t ack_status_lock;
@@ -1150,8 +1156,7 @@ struct ieee80211_local {
 
        /* virtual monitor interface */
        struct ieee80211_sub_if_data __rcu *monitor_sdata;
-       struct ieee80211_channel *monitor_channel;
-       enum nl80211_channel_type monitor_channel_type;
+       struct cfg80211_chan_def monitor_chandef;
 };
 
 static inline struct ieee80211_sub_if_data *
@@ -1251,7 +1256,18 @@ static inline int ieee80211_bssid_match(const u8 *raddr, const u8 *addr)
               is_broadcast_ether_addr(raddr);
 }
 
+static inline bool
+ieee80211_have_rx_timestamp(struct ieee80211_rx_status *status)
+{
+       WARN_ON_ONCE(status->flag & RX_FLAG_MACTIME_START &&
+                    status->flag & RX_FLAG_MACTIME_END);
+       return status->flag & (RX_FLAG_MACTIME_START | RX_FLAG_MACTIME_END);
+}
 
+u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
+                                    struct ieee80211_rx_status *status,
+                                    unsigned int mpdu_len,
+                                    unsigned int mpdu_offset);
 int ieee80211_hw_config(struct ieee80211_local *local, u32 changed);
 void ieee80211_tx_set_protected(struct ieee80211_tx_data *tx);
 void ieee80211_bss_info_change_notify(struct ieee80211_sub_if_data *sdata,
@@ -1365,6 +1381,9 @@ void ieee80211_adjust_monitor_flags(struct ieee80211_sub_if_data *sdata,
 int ieee80211_do_open(struct wireless_dev *wdev, bool coming_up);
 void ieee80211_sdata_stop(struct ieee80211_sub_if_data *sdata);
 
+bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
+void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata);
+
 static inline bool ieee80211_sdata_running(struct ieee80211_sub_if_data *sdata)
 {
        return test_bit(SDATA_STATE_RUNNING, &sdata->state);
@@ -1496,7 +1515,7 @@ static inline void ieee80211_tx_skb_tid(struct ieee80211_sub_if_data *sdata,
        }
 
        __ieee80211_tx_skb_tid_band(sdata, skb, tid,
-                                   chanctx_conf->channel->band);
+                                   chanctx_conf->def.chan->band);
        rcu_read_unlock();
 }
 
@@ -1585,8 +1604,7 @@ size_t ieee80211_ie_split_vendor(const u8 *ies, size_t ielen, size_t offset);
 u8 *ieee80211_ie_build_ht_cap(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
                              u16 cap);
 u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
-                              struct ieee80211_channel *channel,
-                              enum nl80211_channel_type channel_type,
+                              const struct cfg80211_chan_def *chandef,
                               u16 prot_mode);
 u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
                               u32 cap);
@@ -1598,13 +1616,13 @@ int ieee80211_add_ext_srates_ie(struct ieee80211_sub_if_data *sdata,
                                enum ieee80211_band band);
 
 /* channel management */
-enum nl80211_channel_type
-ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper);
+void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
+                                 struct ieee80211_ht_operation *ht_oper,
+                                 struct cfg80211_chan_def *chandef);
 
 int __must_check
 ieee80211_vif_use_channel(struct ieee80211_sub_if_data *sdata,
-                         struct ieee80211_channel *channel,
-                         enum nl80211_channel_type channel_type,
+                         const struct cfg80211_chan_def *chandef,
                          enum ieee80211_chanctx_mode mode);
 void ieee80211_vif_release_channel(struct ieee80211_sub_if_data *sdata);
 
index bc3e3e1db093aac04a87eafcec51b824dc81c8f2..5331662489f7ed30a12e62d638228f3114c4cca1 100644 (file)
  * by either the RTNL, the iflist_mtx or RCU.
  */
 
+bool __ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
+{
+       struct ieee80211_chanctx_conf *chanctx_conf;
+       int power;
+
+       rcu_read_lock();
+       chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
+       if (!chanctx_conf) {
+               rcu_read_unlock();
+               return false;
+       }
+
+       power = chanctx_conf->def.chan->max_power;
+       rcu_read_unlock();
+
+       if (sdata->user_power_level != IEEE80211_UNSET_POWER_LEVEL)
+               power = min(power, sdata->user_power_level);
+
+       if (sdata->ap_power_level != IEEE80211_UNSET_POWER_LEVEL)
+               power = min(power, sdata->ap_power_level);
+
+       if (power != sdata->vif.bss_conf.txpower) {
+               sdata->vif.bss_conf.txpower = power;
+               ieee80211_hw_config(sdata->local, 0);
+               return true;
+       }
+
+       return false;
+}
+
+void ieee80211_recalc_txpower(struct ieee80211_sub_if_data *sdata)
+{
+       if (__ieee80211_recalc_txpower(sdata))
+               ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_TXPOWER);
+}
 
 static u32 ieee80211_idle_off(struct ieee80211_local *local,
                              const char *reason)
@@ -380,8 +415,7 @@ static int ieee80211_add_virtual_monitor(struct ieee80211_local *local)
                goto out_unlock;
        }
 
-       ret = ieee80211_vif_use_channel(sdata, local->monitor_channel,
-                                       local->monitor_channel_type,
+       ret = ieee80211_vif_use_channel(sdata, &local->monitor_chandef,
                                        IEEE80211_CHANCTX_EXCLUSIVE);
        if (ret) {
                drv_remove_interface(local, sdata);
@@ -744,31 +778,12 @@ static void ieee80211_do_stop(struct ieee80211_sub_if_data *sdata,
        /* APs need special treatment */
        if (sdata->vif.type == NL80211_IFTYPE_AP) {
                struct ieee80211_sub_if_data *vlan, *tmpsdata;
-               struct beacon_data *old_beacon =
-                       rtnl_dereference(sdata->u.ap.beacon);
-               struct probe_resp *old_probe_resp =
-                       rtnl_dereference(sdata->u.ap.probe_resp);
-
-               /* sdata_running will return false, so this will disable */
-               ieee80211_bss_info_change_notify(sdata,
-                                                BSS_CHANGED_BEACON_ENABLED);
-
-               /* remove beacon and probe response */
-               RCU_INIT_POINTER(sdata->u.ap.beacon, NULL);
-               RCU_INIT_POINTER(sdata->u.ap.probe_resp, NULL);
-               synchronize_rcu();
-               kfree(old_beacon);
-               kfree(old_probe_resp);
 
                /* down all dependent devices, that is VLANs */
                list_for_each_entry_safe(vlan, tmpsdata, &sdata->u.ap.vlans,
                                         u.vlan.list)
                        dev_close(vlan->dev);
                WARN_ON(!list_empty(&sdata->u.ap.vlans));
-
-               /* free all potentially still buffered bcast frames */
-               local->total_ps_buffered -= skb_queue_len(&sdata->u.ap.ps.bc_buf);
-               skb_queue_purge(&sdata->u.ap.ps.bc_buf);
        } else if (sdata->vif.type == NL80211_IFTYPE_STATION) {
                ieee80211_mgd_stop(sdata);
        }
@@ -1529,6 +1544,9 @@ int ieee80211_if_add(struct ieee80211_local *local, const char *name,
 
        ieee80211_set_default_queues(sdata);
 
+       sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
+       sdata->user_power_level = local->user_power_level;
+
        /* setup type-dependent data */
        ieee80211_setup_sdata(sdata, type);
 
index d27e61aaa71bd7200c527606820f5d5d82c39ff0..619c5d69799980108c03fc3c0c7d6b2553aebb6e 100644 (file)
@@ -339,7 +339,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                key->conf.iv_len = TKIP_IV_LEN;
                key->conf.icv_len = TKIP_ICV_LEN;
                if (seq) {
-                       for (i = 0; i < NUM_RX_DATA_QUEUES; i++) {
+                       for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
                                key->u.tkip.rx[i].iv32 =
                                        get_unaligned_le32(&seq[2]);
                                key->u.tkip.rx[i].iv16 =
@@ -352,7 +352,7 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                key->conf.iv_len = CCMP_HDR_LEN;
                key->conf.icv_len = CCMP_MIC_LEN;
                if (seq) {
-                       for (i = 0; i < NUM_RX_DATA_QUEUES + 1; i++)
+                       for (i = 0; i < IEEE80211_NUM_TIDS + 1; i++)
                                for (j = 0; j < CCMP_PN_LEN; j++)
                                        key->u.ccmp.rx_pn[i][j] =
                                                seq[CCMP_PN_LEN - j - 1];
@@ -372,8 +372,9 @@ struct ieee80211_key *ieee80211_key_alloc(u32 cipher, int idx, size_t key_len,
                key->conf.iv_len = 0;
                key->conf.icv_len = sizeof(struct ieee80211_mmie);
                if (seq)
-                       for (j = 0; j < 6; j++)
-                               key->u.aes_cmac.rx_pn[j] = seq[6 - j - 1];
+                       for (j = 0; j < CMAC_PN_LEN; j++)
+                               key->u.aes_cmac.rx_pn[j] =
+                                       seq[CMAC_PN_LEN - j - 1];
                /*
                 * Initialize AES key state here as an optimization so that
                 * it does not need to be initialized for every packet.
@@ -654,16 +655,16 @@ void ieee80211_get_key_rx_seq(struct ieee80211_key_conf *keyconf,
 
        switch (key->conf.cipher) {
        case WLAN_CIPHER_SUITE_TKIP:
-               if (WARN_ON(tid < 0 || tid >= NUM_RX_DATA_QUEUES))
+               if (WARN_ON(tid < 0 || tid >= IEEE80211_NUM_TIDS))
                        return;
                seq->tkip.iv32 = key->u.tkip.rx[tid].iv32;
                seq->tkip.iv16 = key->u.tkip.rx[tid].iv16;
                break;
        case WLAN_CIPHER_SUITE_CCMP:
-               if (WARN_ON(tid < -1 || tid >= NUM_RX_DATA_QUEUES))
+               if (WARN_ON(tid < -1 || tid >= IEEE80211_NUM_TIDS))
                        return;
                if (tid < 0)
-                       pn = key->u.ccmp.rx_pn[NUM_RX_DATA_QUEUES];
+                       pn = key->u.ccmp.rx_pn[IEEE80211_NUM_TIDS];
                else
                        pn = key->u.ccmp.rx_pn[tid];
                memcpy(seq->ccmp.pn, pn, CCMP_PN_LEN);
index 7d4e31f037d7c4237e18783ec5ebf18cbc8dba52..7cff0d3a519c081b586b6a3cc93fc5d69ea39f3b 100644 (file)
@@ -30,8 +30,6 @@
 #define TKIP_ICV_LEN           4
 #define CMAC_PN_LEN            6
 
-#define NUM_RX_DATA_QUEUES     16
-
 struct ieee80211_local;
 struct ieee80211_sub_if_data;
 struct sta_info;
@@ -82,17 +80,17 @@ struct ieee80211_key {
                        struct tkip_ctx tx;
 
                        /* last received RSC */
-                       struct tkip_ctx rx[NUM_RX_DATA_QUEUES];
+                       struct tkip_ctx rx[IEEE80211_NUM_TIDS];
                } tkip;
                struct {
                        atomic64_t tx_pn;
                        /*
                         * Last received packet number. The first
-                        * NUM_RX_DATA_QUEUES counters are used with Data
+                        * IEEE80211_NUM_TIDS counters are used with Data
                         * frames and the last counter is used with Robust
                         * Management frames.
                         */
-                       u8 rx_pn[NUM_RX_DATA_QUEUES + 1][CCMP_PN_LEN];
+                       u8 rx_pn[IEEE80211_NUM_TIDS + 1][CCMP_PN_LEN];
                        struct crypto_cipher *tfm;
                        u32 replays; /* dot11RSNAStatsCCMPReplays */
                } ccmp;
index d6e43b08d6293a292ef92ea65e4d395d17d9b838..f5e4c1f24bf29d7d0fe0ae0d802a29c8856d7f93 100644 (file)
@@ -95,11 +95,13 @@ static void ieee80211_reconfig_filter(struct work_struct *work)
 
 static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
 {
+       struct ieee80211_sub_if_data *sdata;
        struct ieee80211_channel *chan;
        u32 changed = 0;
        int power;
        enum nl80211_channel_type channel_type;
        u32 offchannel_flag;
+       bool scanning = false;
 
        offchannel_flag = local->hw.conf.flags & IEEE80211_CONF_OFFCHANNEL;
        if (local->scan_channel) {
@@ -113,7 +115,7 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
                        channel_type = NL80211_CHAN_NO_HT;
        } else if (local->tmp_channel) {
                chan = local->tmp_channel;
-               channel_type = local->tmp_channel_type;
+               channel_type = NL80211_CHAN_NO_HT;
        } else {
                chan = local->_oper_channel;
                channel_type = local->_oper_channel_type;
@@ -146,16 +148,18 @@ static u32 ieee80211_hw_conf_chan(struct ieee80211_local *local)
                changed |= IEEE80211_CONF_CHANGE_SMPS;
        }
 
-       if (test_bit(SCAN_SW_SCANNING, &local->scanning) ||
-           test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
-           test_bit(SCAN_HW_SCANNING, &local->scanning) ||
-           !local->ap_power_level)
-               power = chan->max_power;
-       else
-               power = min(chan->max_power, local->ap_power_level);
+       scanning = test_bit(SCAN_SW_SCANNING, &local->scanning) ||
+                  test_bit(SCAN_ONCHANNEL_SCANNING, &local->scanning) ||
+                  test_bit(SCAN_HW_SCANNING, &local->scanning);
+       power = chan->max_power;
 
-       if (local->user_power_level >= 0)
-               power = min(power, local->user_power_level);
+       rcu_read_lock();
+       list_for_each_entry_rcu(sdata, &local->interfaces, list) {
+               if (!rcu_access_pointer(sdata->vif.chanctx_conf))
+                       continue;
+               power = min(power, sdata->vif.bss_conf.txpower);
+       }
+       rcu_read_unlock();
 
        if (local->hw.conf.power_level != power) {
                changed |= IEEE80211_CONF_CHANGE_POWER;
@@ -600,7 +604,8 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
 
        wiphy->features |= NL80211_FEATURE_SK_TX_STATUS |
                           NL80211_FEATURE_SAE |
-                          NL80211_FEATURE_HT_IBSS;
+                          NL80211_FEATURE_HT_IBSS |
+                          NL80211_FEATURE_VIF_TXPOWER;
 
        if (!ops->hw_scan)
                wiphy->features |= NL80211_FEATURE_LOW_PRIORITY_SCAN |
@@ -633,7 +638,7 @@ struct ieee80211_hw *ieee80211_alloc_hw(size_t priv_data_len,
        local->hw.radiotap_mcs_details = IEEE80211_RADIOTAP_MCS_HAVE_MCS |
                                         IEEE80211_RADIOTAP_MCS_HAVE_GI |
                                         IEEE80211_RADIOTAP_MCS_HAVE_BW;
-       local->user_power_level = -1;
+       local->user_power_level = IEEE80211_UNSET_POWER_LEVEL;
        wiphy->ht_capa_mod_mask = &mac80211_ht_capa_mod_mask;
 
        INIT_LIST_HEAD(&local->interfaces);
@@ -793,10 +798,9 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
                        local->_oper_channel = &sband->channels[0];
                        local->hw.conf.channel_type = NL80211_CHAN_NO_HT;
                }
-               if (!local->monitor_channel) {
-                       local->monitor_channel = &sband->channels[0];
-                       local->monitor_channel_type = NL80211_CHAN_NO_HT;
-               }
+               cfg80211_chandef_create(&local->monitor_chandef,
+                                       &sband->channels[0],
+                                       NL80211_CHAN_NO_HT);
                channels += sband->n_channels;
 
                if (max_bitrates < sband->n_bitrates)
@@ -879,10 +883,22 @@ int ieee80211_register_hw(struct ieee80211_hw *hw)
        if (supp_ht)
                local->scan_ies_len += 2 + sizeof(struct ieee80211_ht_cap);
 
-       if (supp_vht)
+       if (supp_vht) {
                local->scan_ies_len +=
                        2 + sizeof(struct ieee80211_vht_cap);
 
+               /*
+                * (for now at least), drivers wanting to use VHT must
+                * support channel contexts, as they contain all the
+                * necessary VHT information and the global hw config
+                * doesn't (yet)
+                */
+               if (WARN_ON(!local->use_chanctx)) {
+                       result = -EINVAL;
+                       goto fail_wiphy_register;
+               }
+       }
+
        if (!local->ops->hw_scan) {
                /* For hw_scan, driver needs to set these up. */
                local->hw.wiphy->max_scan_ssids = 4;
index a350cab4b339aad727157d66de9f1887f3da6ebd..1bf03f9ff3ba74394fb26201dfba3b3fd2e86a01 100644 (file)
@@ -76,7 +76,7 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_mesh *ifmsh = &sdata->u.mesh;
        struct ieee80211_local *local = sdata->local;
        u32 basic_rates = 0;
-       enum nl80211_channel_type sta_channel_type = NL80211_CHAN_NO_HT;
+       struct cfg80211_chan_def sta_chan_def;
 
        /*
         * As support for each feature is added, check for matching
@@ -103,17 +103,11 @@ bool mesh_matches_local(struct ieee80211_sub_if_data *sdata,
        if (sdata->vif.bss_conf.basic_rates != basic_rates)
                goto mismatch;
 
-       if (ie->ht_operation)
-               sta_channel_type =
-                       ieee80211_ht_oper_to_channel_type(ie->ht_operation);
-
-       /* Disallow HT40+/- mismatch */
-       if (ie->ht_operation &&
-           (sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40MINUS ||
-            sdata->vif.bss_conf.channel_type == NL80211_CHAN_HT40PLUS) &&
-           (sta_channel_type == NL80211_CHAN_HT40MINUS ||
-            sta_channel_type == NL80211_CHAN_HT40PLUS) &&
-           sdata->vif.bss_conf.channel_type != sta_channel_type)
+       ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
+                                    ie->ht_operation, &sta_chan_def);
+
+       if (!cfg80211_chandef_compatible(&sdata->vif.bss_conf.chandef,
+                                        &sta_chan_def))
                goto mismatch;
 
        return true;
@@ -129,7 +123,7 @@ mismatch:
 bool mesh_peer_accepts_plinks(struct ieee802_11_elems *ie)
 {
        return (ie->mesh_config->meshconf_cap &
-           MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
+           IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS) != 0;
 }
 
 /**
@@ -269,11 +263,11 @@ mesh_add_meshconf_ie(struct sk_buff *skb, struct ieee80211_sub_if_data *sdata)
        neighbors = (neighbors > 15) ? 15 : neighbors;
        *pos++ = neighbors << 1;
        /* Mesh capability */
-       *pos = MESHCONF_CAPAB_FORWARDING;
+       *pos = IEEE80211_MESHCONF_CAPAB_FORWARDING;
        *pos |= ifmsh->accepting_plinks ?
-           MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
+           IEEE80211_MESHCONF_CAPAB_ACCEPT_PLINKS : 0x00;
        *pos++ |= ifmsh->adjusting_tbtt ?
-           MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
+           IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING : 0x00;
        *pos++ = 0x00;
 
        return 0;
@@ -368,7 +362,7 @@ int mesh_add_ds_params_ie(struct sk_buff *skb,
                rcu_read_unlock();
                return -EINVAL;
        }
-       chan = chanctx_conf->channel;
+       chan = chanctx_conf->def.chan;
        rcu_read_unlock();
 
        sband = local->hw.wiphy->bands[chan->band];
@@ -392,7 +386,7 @@ int mesh_add_ht_cap_ie(struct sk_buff *skb,
 
        sband = local->hw.wiphy->bands[band];
        if (!sband->ht_cap.ht_supported ||
-           sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
+           sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
                return 0;
 
        if (skb_tailroom(skb) < 2 + sizeof(struct ieee80211_ht_cap))
@@ -411,7 +405,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
        struct ieee80211_chanctx_conf *chanctx_conf;
        struct ieee80211_channel *channel;
        enum nl80211_channel_type channel_type =
-               sdata->vif.bss_conf.channel_type;
+               cfg80211_get_chandef_type(&sdata->vif.bss_conf.chandef);
        struct ieee80211_supported_band *sband;
        struct ieee80211_sta_ht_cap *ht_cap;
        u8 *pos;
@@ -422,7 +416,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
                rcu_read_unlock();
                return -EINVAL;
        }
-       channel = chanctx_conf->channel;
+       channel = chanctx_conf->def.chan;
        rcu_read_unlock();
 
        sband = local->hw.wiphy->bands[channel->band];
@@ -435,7 +429,7 @@ int mesh_add_ht_oper_ie(struct sk_buff *skb,
                return -ENOMEM;
 
        pos = skb_put(skb, 2 + sizeof(struct ieee80211_ht_operation));
-       ieee80211_ie_build_ht_oper(pos, ht_cap, channel, channel_type,
+       ieee80211_ie_build_ht_oper(pos, ht_cap, &sdata->vif.bss_conf.chandef,
                                   sdata->vif.bss_conf.ht_operation_mode);
 
        return 0;
index 9285f3f67e6634901ee494a1dd66c15c4cfa4dba..7c9215fb2ac84ec5c17d3ee3d372a7a6bb4feedc 100644 (file)
 
 /* Data structures */
 
-/**
- * enum mesh_config_capab_flags - mesh config IE capability flags
- *
- * @MESHCONF_CAPAB_ACCEPT_PLINKS: STA is willing to establish
- * additional mesh peerings with other mesh STAs
- * @MESHCONF_CAPAB_FORWARDING: the STA forwards MSDUs
- * @MESHCONF_CAPAB_TBTT_ADJUSTING: TBTT adjustment procedure is ongoing
- */
-enum mesh_config_capab_flags {
-       MESHCONF_CAPAB_ACCEPT_PLINKS = BIT(0),
-       MESHCONF_CAPAB_FORWARDING = BIT(3),
-       MESHCONF_CAPAB_TBTT_ADJUSTING = BIT(5),
-};
-
 /**
  * enum mesh_path_flags - mac80211 mesh path flags
  *
index 234fe755968bfae25bfd307637f1afe710bf2ae7..ca52dfdd5375cdb8a63049410a1a81b3c715a685 100644 (file)
 #define mod_plink_timer(s, t) (mod_timer(&s->plink_timer, \
                                jiffies + HZ * t / 1000))
 
-#define dot11MeshMaxRetries(s) (s->u.mesh.mshcfg.dot11MeshMaxRetries)
-#define dot11MeshRetryTimeout(s) (s->u.mesh.mshcfg.dot11MeshRetryTimeout)
-#define dot11MeshConfirmTimeout(s) (s->u.mesh.mshcfg.dot11MeshConfirmTimeout)
-#define dot11MeshHoldingTimeout(s) (s->u.mesh.mshcfg.dot11MeshHoldingTimeout)
-#define dot11MeshMaxPeerLinks(s) (s->u.mesh.mshcfg.dot11MeshMaxPeerLinks)
-
 /* We only need a valid sta if user configured a minimum rssi_threshold. */
 #define rssi_threshold_check(sta, sdata) \
                (sdata->u.mesh.mshcfg.rssi_threshold == 0 ||\
@@ -117,7 +111,7 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
        u16 ht_opmode;
        bool non_ht_sta = false, ht20_sta = false;
 
-       if (sdata->vif.bss_conf.channel_type == NL80211_CHAN_NO_HT)
+       if (sdata->vif.bss_conf.chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
                return 0;
 
        rcu_read_lock();
@@ -126,14 +120,14 @@ static u32 mesh_set_ht_prot_mode(struct ieee80211_sub_if_data *sdata)
                    sta->plink_state != NL80211_PLINK_ESTAB)
                        continue;
 
-               switch (sta->ch_type) {
-               case NL80211_CHAN_NO_HT:
+               switch (sta->ch_width) {
+               case NL80211_CHAN_WIDTH_20_NOHT:
                        mpl_dbg(sdata,
                                "mesh_plink %pM: nonHT sta (%pM) is present\n",
                                sdata->vif.addr, sta->sta.addr);
                        non_ht_sta = true;
                        goto out;
-               case NL80211_CHAN_HT20:
+               case NL80211_CHAN_WIDTH_20:
                        mpl_dbg(sdata,
                                "mesh_plink %pM: HT20 sta (%pM) is present\n",
                                sdata->vif.addr, sta->sta.addr);
@@ -148,7 +142,7 @@ out:
        if (non_ht_sta)
                ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONHT_MIXED;
        else if (ht20_sta &&
-                sdata->vif.bss_conf.channel_type > NL80211_CHAN_HT20)
+                sdata->vif.bss_conf.chandef.width > NL80211_CHAN_WIDTH_20)
                ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_20MHZ;
        else
                ht_opmode = IEEE80211_HT_OP_MODE_PROTECTION_NONE;
@@ -378,7 +372,7 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
 
        sta->sta.supp_rates[band] = rates;
        if (elems->ht_cap_elem &&
-           sdata->vif.bss_conf.channel_type != NL80211_CHAN_NO_HT)
+           sdata->vif.bss_conf.chandef.width != NL80211_CHAN_WIDTH_20_NOHT)
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                                  elems->ht_cap_elem,
                                                  &sta->sta.ht_cap);
@@ -386,12 +380,15 @@ static struct sta_info *mesh_peer_init(struct ieee80211_sub_if_data *sdata,
                memset(&sta->sta.ht_cap, 0, sizeof(sta->sta.ht_cap));
 
        if (elems->ht_operation) {
+               struct cfg80211_chan_def chandef;
+
                if (!(elems->ht_operation->ht_param &
                      IEEE80211_HT_PARAM_CHAN_WIDTH_ANY))
                        sta->sta.ht_cap.cap &=
                                            ~IEEE80211_HT_CAP_SUP_WIDTH_20_40;
-               sta->ch_type =
-                       ieee80211_ht_oper_to_channel_type(elems->ht_operation);
+               ieee80211_ht_oper_to_chandef(sdata->vif.bss_conf.chandef.chan,
+                                            elems->ht_operation, &chandef);
+               sta->ch_width = chandef.width;
        }
 
        rate_control_rate_init(sta);
@@ -430,6 +427,7 @@ static void mesh_plink_timer(unsigned long data)
        struct sta_info *sta;
        __le16 llid, plid, reason;
        struct ieee80211_sub_if_data *sdata;
+       struct mesh_config *mshcfg;
 
        /*
         * This STA is valid because sta_info_destroy() will
@@ -456,12 +454,13 @@ static void mesh_plink_timer(unsigned long data)
        llid = sta->llid;
        plid = sta->plid;
        sdata = sta->sdata;
+       mshcfg = &sdata->u.mesh.mshcfg;
 
        switch (sta->plink_state) {
        case NL80211_PLINK_OPN_RCVD:
        case NL80211_PLINK_OPN_SNT:
                /* retry timer */
-               if (sta->plink_retries < dot11MeshMaxRetries(sdata)) {
+               if (sta->plink_retries < mshcfg->dot11MeshMaxRetries) {
                        u32 rand;
                        mpl_dbg(sta->sdata,
                                "Mesh plink for %pM (retry, timeout): %d %d\n",
@@ -484,7 +483,7 @@ static void mesh_plink_timer(unsigned long data)
                if (!reason)
                        reason = cpu_to_le16(WLAN_REASON_MESH_CONFIRM_TIMEOUT);
                sta->plink_state = NL80211_PLINK_HOLDING;
-               mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
+               mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
                spin_unlock_bh(&sta->lock);
                mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
                                    sta->sta.addr, llid, plid, reason);
@@ -543,7 +542,7 @@ int mesh_plink_open(struct sta_info *sta)
                return -EBUSY;
        }
        sta->plink_state = NL80211_PLINK_OPN_SNT;
-       mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
+       mesh_plink_timer_set(sta, sdata->u.mesh.mshcfg.dot11MeshRetryTimeout);
        spin_unlock_bh(&sta->lock);
        mpl_dbg(sdata,
                "Mesh plink: starting establishment with %pM\n",
@@ -570,6 +569,7 @@ void mesh_plink_block(struct sta_info *sta)
 void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_mgmt *mgmt,
                         size_t len, struct ieee80211_rx_status *rx_status)
 {
+       struct mesh_config *mshcfg = &sdata->u.mesh.mshcfg;
        struct ieee802_11_elems elems;
        struct sta_info *sta;
        enum plink_event event;
@@ -777,7 +777,8 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                        sta->plid = plid;
                        get_random_bytes(&llid, 2);
                        sta->llid = llid;
-                       mesh_plink_timer_set(sta, dot11MeshRetryTimeout(sdata));
+                       mesh_plink_timer_set(sta,
+                                            mshcfg->dot11MeshRetryTimeout);
                        spin_unlock_bh(&sta->lock);
                        mesh_plink_frame_tx(sdata,
                                            WLAN_SP_MESH_PEERING_OPEN,
@@ -803,7 +804,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                        sta->reason = reason;
                        sta->plink_state = NL80211_PLINK_HOLDING;
                        if (!mod_plink_timer(sta,
-                                            dot11MeshHoldingTimeout(sdata)))
+                                            mshcfg->dot11MeshHoldingTimeout))
                                sta->ignore_plink_timer = true;
 
                        llid = sta->llid;
@@ -825,7 +826,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                case CNF_ACPT:
                        sta->plink_state = NL80211_PLINK_CNF_RCVD;
                        if (!mod_plink_timer(sta,
-                                            dot11MeshConfirmTimeout(sdata)))
+                                            mshcfg->dot11MeshConfirmTimeout))
                                sta->ignore_plink_timer = true;
 
                        spin_unlock_bh(&sta->lock);
@@ -847,7 +848,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                        sta->reason = reason;
                        sta->plink_state = NL80211_PLINK_HOLDING;
                        if (!mod_plink_timer(sta,
-                                            dot11MeshHoldingTimeout(sdata)))
+                                            mshcfg->dot11MeshHoldingTimeout))
                                sta->ignore_plink_timer = true;
 
                        llid = sta->llid;
@@ -888,7 +889,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                        sta->reason = reason;
                        sta->plink_state = NL80211_PLINK_HOLDING;
                        if (!mod_plink_timer(sta,
-                                            dot11MeshHoldingTimeout(sdata)))
+                                            mshcfg->dot11MeshHoldingTimeout))
                                sta->ignore_plink_timer = true;
 
                        llid = sta->llid;
@@ -923,7 +924,7 @@ void mesh_rx_plink_frame(struct ieee80211_sub_if_data *sdata, struct ieee80211_m
                        changed |= __mesh_plink_deactivate(sta);
                        sta->plink_state = NL80211_PLINK_HOLDING;
                        llid = sta->llid;
-                       mod_plink_timer(sta, dot11MeshHoldingTimeout(sdata));
+                       mod_plink_timer(sta, mshcfg->dot11MeshHoldingTimeout);
                        spin_unlock_bh(&sta->lock);
                        changed |= mesh_set_ht_prot_mode(sdata);
                        mesh_plink_frame_tx(sdata, WLAN_SP_MESH_PEERING_CLOSE,
index 407c8705e10d30fed4cf50f322178a1c2d4dc308..0f40086cce18bf06a7d19daa895fd64e72dad6ad 100644 (file)
@@ -43,7 +43,7 @@ struct sync_method {
 static bool mesh_peer_tbtt_adjusting(struct ieee802_11_elems *ie)
 {
        return (ie->mesh_config->meshconf_cap &
-           MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
+           IEEE80211_MESHCONF_CAPAB_TBTT_ADJUSTING) != 0;
 }
 
 void mesh_sync_adjust_tbtt(struct ieee80211_sub_if_data *sdata)
@@ -116,43 +116,13 @@ static void mesh_sync_offset_rx_bcn_presp(struct ieee80211_sub_if_data *sdata,
                goto no_sync;
        }
 
-       if (rx_status->flag & RX_FLAG_MACTIME_MPDU && rx_status->mactime) {
-               /*
-                * The mactime is defined as the time the first data symbol
-                * of the frame hits the PHY, and the timestamp of the beacon
-                * is defined as "the time that the data symbol containing the
-                * first bit of the timestamp is transmitted to the PHY plus
-                * the transmitting STA's delays through its local PHY from the
-                * MAC-PHY interface to its interface with the WM" (802.11
-                * 11.1.2)
-                *
-                * T_r, in 13.13.2.2.2, is just defined as "the frame reception
-                * time" but we unless we interpret that time to be the same
-                * time of the beacon timestamp, the offset calculation will be
-                * off.  Below we adjust t_r to be "the time at which the first
-                * symbol of the timestamp element in the beacon is received".
-                * This correction depends on the rate.
-                *
-                * Based on similar code in ibss.c
-                */
-               int rate;
-
-               if (rx_status->flag & RX_FLAG_HT) {
-                       /* TODO:
-                        * In principle there could be HT-beacons (Dual Beacon
-                        * HT Operation options), but for now ignore them and
-                        * just use the primary (i.e. non-HT) beacons for
-                        * synchronization.
-                        * */
-                       goto no_sync;
-               } else
-                       rate = local->hw.wiphy->bands[rx_status->band]->
-                               bitrates[rx_status->rate_idx].bitrate;
-
-               /* 24 bytes of header * 8 bits/byte *
-                * 10*(100 Kbps)/Mbps / rate (100 Kbps)*/
-               t_r = rx_status->mactime + (24 * 8 * 10 / rate);
-       }
+       if (ieee80211_have_rx_timestamp(rx_status))
+               /* time when timestamp field was received */
+               t_r = ieee80211_calculate_rx_timestamp(local, rx_status,
+                                                      24 + 12 +
+                                                      elems->total_len +
+                                                      FCS_LEN,
+                                                      24);
 
        /* Timing offset calculation (see 13.13.2.2.2) */
        t_t = le64_to_cpu(mgmt->u.beacon.timestamp);
index 1d1fdf0791f06e96ef56ee039f62c070d45b0371..d2a4f78b4b0f658e44022d8cd6fe2b80cbff591e 100644 (file)
@@ -191,17 +191,19 @@ static u32 ieee80211_config_ht_tx(struct ieee80211_sub_if_data *sdata,
                rcu_read_unlock();
                return 0;
        }
-       chan = chanctx_conf->channel;
+       chan = chanctx_conf->def.chan;
        rcu_read_unlock();
        sband = local->hw.wiphy->bands[chan->band];
 
-       switch (sdata->vif.bss_conf.channel_type) {
-       case NL80211_CHAN_HT40PLUS:
-               if (chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
+       switch (sdata->vif.bss_conf.chandef.width) {
+       case NL80211_CHAN_WIDTH_40:
+               if (sdata->vif.bss_conf.chandef.chan->center_freq >
+                               sdata->vif.bss_conf.chandef.center_freq1 &&
+                   chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
                        disable_40 = true;
-               break;
-       case NL80211_CHAN_HT40MINUS:
-               if (chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+               if (sdata->vif.bss_conf.chandef.chan->center_freq <
+                               sdata->vif.bss_conf.chandef.center_freq1 &&
+                   chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
                        disable_40 = true;
                break;
        default:
@@ -381,7 +383,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                rcu_read_unlock();
                return;
        }
-       chan = chanctx_conf->channel;
+       chan = chanctx_conf->def.chan;
        rcu_read_unlock();
        sband = local->hw.wiphy->bands[chan->band];
 
@@ -541,7 +543,7 @@ static void ieee80211_send_assoc(struct ieee80211_sub_if_data *sdata)
                offset = noffset;
        }
 
-       if (!(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
+       if (!(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
                ieee80211_add_ht_ie(sdata, skb, assoc_data->ap_ht_param,
                                    sband, chan, sdata->smps_mode);
 
@@ -820,10 +822,10 @@ void ieee80211_sta_process_chanswitch(struct ieee80211_sub_if_data *sdata,
                                         cbss->beacon_interval));
 }
 
-static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
-                                       struct ieee80211_channel *channel,
-                                       const u8 *country_ie, u8 country_ie_len,
-                                       const u8 *pwr_constr_elem)
+static u32 ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
+                                      struct ieee80211_channel *channel,
+                                      const u8 *country_ie, u8 country_ie_len,
+                                      const u8 *pwr_constr_elem)
 {
        struct ieee80211_country_ie_triplet *triplet;
        int chan = ieee80211_frequency_to_channel(channel->center_freq);
@@ -832,7 +834,7 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
 
        /* Invalid IE */
        if (country_ie_len % 2 || country_ie_len < IEEE80211_COUNTRY_IE_MIN_LEN)
-               return;
+               return 0;
 
        triplet = (void *)(country_ie + 3);
        country_ie_len -= 3;
@@ -873,19 +875,21 @@ static void ieee80211_handle_pwr_constr(struct ieee80211_sub_if_data *sdata,
        }
 
        if (!have_chan_pwr)
-               return;
+               return 0;
 
        new_ap_level = max_t(int, 0, chan_pwr - *pwr_constr_elem);
 
-       if (sdata->local->ap_power_level == new_ap_level)
-               return;
+       if (sdata->ap_power_level == new_ap_level)
+               return 0;
 
        sdata_info(sdata,
                   "Limiting TX power to %d (%d - %d) dBm as advertised by %pM\n",
                   new_ap_level, chan_pwr, *pwr_constr_elem,
                   sdata->u.mgd.bssid);
-       sdata->local->ap_power_level = new_ap_level;
-       ieee80211_hw_config(sdata->local, 0);
+       sdata->ap_power_level = new_ap_level;
+       if (__ieee80211_recalc_txpower(sdata))
+               return BSS_CHANGED_TXPOWER;
+       return 0;
 }
 
 void ieee80211_enable_dyn_ps(struct ieee80211_vif *vif)
@@ -1363,6 +1367,22 @@ static void ieee80211_set_associated(struct ieee80211_sub_if_data *sdata,
 
        sdata->u.mgd.flags |= IEEE80211_STA_RESET_SIGNAL_AVE;
 
+       if (sdata->vif.p2p) {
+               u8 noa[2];
+               int ret;
+
+               ret = cfg80211_get_p2p_attr(cbss->information_elements,
+                                           cbss->len_information_elements,
+                                           IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
+                                           noa, sizeof(noa));
+               if (ret >= 2) {
+                       bss_conf->p2p_oppps = noa[1] & 0x80;
+                       bss_conf->p2p_ctwindow = noa[1] & 0x7f;
+                       bss_info_changed |= BSS_CHANGED_P2P_PS;
+                       sdata->u.mgd.p2p_noa_index = noa[0];
+               }
+       }
+
        /* just to be sure */
        ieee80211_stop_poll(sdata);
 
@@ -1485,11 +1505,14 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        changed |= BSS_CHANGED_ASSOC;
        sdata->vif.bss_conf.assoc = false;
 
+       sdata->vif.bss_conf.p2p_ctwindow = 0;
+       sdata->vif.bss_conf.p2p_oppps = false;
+
        /* on the next assoc, re-program HT parameters */
        memset(&ifmgd->ht_capa, 0, sizeof(ifmgd->ht_capa));
        memset(&ifmgd->ht_capa_mask, 0, sizeof(ifmgd->ht_capa_mask));
 
-       local->ap_power_level = 0;
+       sdata->ap_power_level = IEEE80211_UNSET_POWER_LEVEL;
 
        del_timer_sync(&local->dynamic_ps_timer);
        cancel_work_sync(&local->dynamic_ps_enable_work);
@@ -1507,8 +1530,6 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        changed |= BSS_CHANGED_BSSID | BSS_CHANGED_HT;
        ieee80211_bss_info_change_notify(sdata, changed);
 
-       ieee80211_vif_release_channel(sdata);
-
        /* disassociated - set to defaults now */
        ieee80211_set_wmm_default(sdata, false);
 
@@ -1518,6 +1539,9 @@ static void ieee80211_set_disassoc(struct ieee80211_sub_if_data *sdata,
        del_timer_sync(&sdata->u.mgd.chswitch_timer);
 
        sdata->u.mgd.timers_running = 0;
+
+       ifmgd->flags = 0;
+       ieee80211_vif_release_channel(sdata);
 }
 
 void ieee80211_sta_rx_notify(struct ieee80211_sub_if_data *sdata,
@@ -1843,6 +1867,7 @@ static void ieee80211_destroy_auth_data(struct ieee80211_sub_if_data *sdata,
 
                memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
+               sdata->u.mgd.flags = 0;
                ieee80211_vif_release_channel(sdata);
        }
 
@@ -2085,6 +2110,7 @@ static void ieee80211_destroy_assoc_data(struct ieee80211_sub_if_data *sdata,
 
                memset(sdata->u.mgd.bssid, 0, ETH_ALEN);
                ieee80211_bss_info_change_notify(sdata, BSS_CHANGED_BSSID);
+               sdata->u.mgd.flags = 0;
                ieee80211_vif_release_channel(sdata);
        }
 
@@ -2149,7 +2175,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
 
        sband = local->hw.wiphy->bands[ieee80211_get_sdata_band(sdata)];
 
-       if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
+       if (elems.ht_cap_elem && !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
                ieee80211_ht_cap_ie_to_sta_ht_cap(sdata, sband,
                                elems.ht_cap_elem, &sta->sta.ht_cap);
 
@@ -2201,7 +2227,7 @@ static bool ieee80211_assoc_success(struct ieee80211_sub_if_data *sdata,
        changed |= BSS_CHANGED_QOS;
 
        if (elems.ht_operation && elems.wmm_param &&
-           !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
+           !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
                changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
                                                  cbss->bssid, false);
 
@@ -2452,11 +2478,11 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
-       if (rx_status->freq != chanctx_conf->channel->center_freq) {
+       if (rx_status->freq != chanctx_conf->def.chan->center_freq) {
                rcu_read_unlock();
                return;
        }
-       chan = chanctx_conf->channel;
+       chan = chanctx_conf->def.chan;
        rcu_read_unlock();
 
        if (ifmgd->assoc_data && !ifmgd->assoc_data->have_beacon &&
@@ -2592,6 +2618,27 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
                }
        }
 
+       if (sdata->vif.p2p) {
+               u8 noa[2];
+               int ret;
+
+               ret = cfg80211_get_p2p_attr(mgmt->u.beacon.variable,
+                                           len - baselen,
+                                           IEEE80211_P2P_ATTR_ABSENCE_NOTICE,
+                                           noa, sizeof(noa));
+               if (ret >= 2 && sdata->u.mgd.p2p_noa_index != noa[0]) {
+                       bss_conf->p2p_oppps = noa[1] & 0x80;
+                       bss_conf->p2p_ctwindow = noa[1] & 0x7f;
+                       changed |= BSS_CHANGED_P2P_PS;
+                       sdata->u.mgd.p2p_noa_index = noa[0];
+                       /*
+                        * make sure we update all information, the CRC
+                        * mechanism doesn't look at P2P attributes.
+                        */
+                       ifmgd->beacon_crc_valid = false;
+               }
+       }
+
        if (ncrc == ifmgd->beacon_crc && ifmgd->beacon_crc_valid)
                return;
        ifmgd->beacon_crc = ncrc;
@@ -2616,17 +2663,17 @@ static void ieee80211_rx_mgmt_beacon(struct ieee80211_sub_if_data *sdata,
 
 
        if (elems.ht_cap_elem && elems.ht_operation && elems.wmm_param &&
-           !(ifmgd->flags & IEEE80211_STA_DISABLE_11N))
+           !(ifmgd->flags & IEEE80211_STA_DISABLE_HT))
                changed |= ieee80211_config_ht_tx(sdata, elems.ht_operation,
                                                  bssid, true);
 
        if (elems.country_elem && elems.pwr_constr_elem &&
            mgmt->u.probe_resp.capab_info &
                                cpu_to_le16(WLAN_CAPABILITY_SPECTRUM_MGMT))
-               ieee80211_handle_pwr_constr(sdata, chan,
-                                           elems.country_elem,
-                                           elems.country_elem_len,
-                                           elems.pwr_constr_elem);
+               changed |= ieee80211_handle_pwr_constr(sdata, chan,
+                                                      elems.country_elem,
+                                                      elems.country_elem_len,
+                                                      elems.pwr_constr_elem);
 
        ieee80211_bss_info_change_notify(sdata, changed);
 }
@@ -3146,6 +3193,7 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
        const u8 *ht_oper_ie;
        const struct ieee80211_ht_operation *ht_oper = NULL;
        struct ieee80211_supported_band *sband;
+       struct cfg80211_chan_def chandef;
 
        sband = local->hw.wiphy->bands[cbss->channel->band];
 
@@ -3177,12 +3225,10 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                                   ht_cfreq, ht_oper->primary_chan,
                                   cbss->channel->band);
                        ht_oper = NULL;
-               } else {
-                       channel_type = NL80211_CHAN_HT20;
                }
        }
 
-       if (ht_oper && sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+       if (ht_oper) {
                /*
                 * cfg80211 already verified that the channel itself can
                 * be used, but it didn't check that we can do the right
@@ -3195,19 +3241,26 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
 
                channel_type = NL80211_CHAN_HT20;
 
-               switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
-               case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
-                       if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40PLUS)
-                               ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
-                       else
-                               channel_type = NL80211_CHAN_HT40PLUS;
-                       break;
-               case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
-                       if (cbss->channel->flags & IEEE80211_CHAN_NO_HT40MINUS)
-                               ifmgd->flags |= IEEE80211_STA_DISABLE_40MHZ;
-                       else
-                               channel_type = NL80211_CHAN_HT40MINUS;
-                       break;
+               if (sband->ht_cap.cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) {
+                       switch (ht_oper->ht_param &
+                                       IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
+                       case IEEE80211_HT_PARAM_CHA_SEC_ABOVE:
+                               if (cbss->channel->flags &
+                                               IEEE80211_CHAN_NO_HT40PLUS)
+                                       ifmgd->flags |=
+                                               IEEE80211_STA_DISABLE_40MHZ;
+                               else
+                                       channel_type = NL80211_CHAN_HT40PLUS;
+                               break;
+                       case IEEE80211_HT_PARAM_CHA_SEC_BELOW:
+                               if (cbss->channel->flags &
+                                               IEEE80211_CHAN_NO_HT40MINUS)
+                                       ifmgd->flags |=
+                                               IEEE80211_STA_DISABLE_40MHZ;
+                               else
+                                       channel_type = NL80211_CHAN_HT40MINUS;
+                               break;
+                       }
                }
 
                ht_cap_ie = cfg80211_find_ie(WLAN_EID_HT_CAPABILITY,
@@ -3220,13 +3273,15 @@ static int ieee80211_prep_channel(struct ieee80211_sub_if_data *sdata,
                sdata->needed_rx_chains = min(chains, local->rx_chains);
        } else {
                sdata->needed_rx_chains = 1;
+               sdata->u.mgd.flags |= IEEE80211_STA_DISABLE_HT;
        }
 
        /* will change later if needed */
        sdata->smps_mode = IEEE80211_SMPS_OFF;
 
        ieee80211_vif_release_channel(sdata);
-       return ieee80211_vif_use_channel(sdata, cbss->channel, channel_type,
+       cfg80211_chandef_create(&chandef, cbss->channel, channel_type);
+       return ieee80211_vif_use_channel(sdata, &chandef,
                                         IEEE80211_CHANCTX_SHARED);
 }
 
@@ -3488,13 +3543,6 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
 
        /* prepare assoc data */
        
-       /*
-        * keep only the 40 MHz disable bit set as it might have
-        * been set during authentication already, all other bits
-        * should be reset for a new connection
-        */
-       ifmgd->flags &= IEEE80211_STA_DISABLE_40MHZ;
-
        ifmgd->beacon_crc_valid = false;
 
        /*
@@ -3508,7 +3556,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                if (req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP40 ||
                    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_TKIP ||
                    req->crypto.ciphers_pairwise[i] == WLAN_CIPHER_SUITE_WEP104) {
-                       ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+                       ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
                        ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
                        netdev_info(sdata->dev,
                                    "disabling HT/VHT due to WEP/TKIP use\n");
@@ -3516,7 +3564,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        }
 
        if (req->flags & ASSOC_REQ_DISABLE_HT) {
-               ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
                ifmgd->flags |= IEEE80211_STA_DISABLE_VHT;
        }
 
@@ -3524,7 +3572,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
        sband = local->hw.wiphy->bands[req->bss->channel->band];
        if (!sband->ht_cap.ht_supported ||
            local->hw.queues < IEEE80211_NUM_ACS || !bss->wmm_used) {
-               ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
                if (!bss->wmm_used)
                        netdev_info(sdata->dev,
                                    "disabling HT as WMM/QoS is not supported by the AP\n");
@@ -3569,7 +3617,7 @@ int ieee80211_mgd_assoc(struct ieee80211_sub_if_data *sdata,
                assoc_data->ap_ht_param =
                        ((struct ieee80211_ht_operation *)(ht_ie + 2))->ht_param;
        else
-               ifmgd->flags |= IEEE80211_STA_DISABLE_11N;
+               ifmgd->flags |= IEEE80211_STA_DISABLE_HT;
 
        if (bss->wmm_used && bss->uapsd_supported &&
            (sdata->local->hw.flags & IEEE80211_HW_SUPPORTS_UAPSD)) {
@@ -3660,40 +3708,44 @@ int ieee80211_mgd_deauth(struct ieee80211_sub_if_data *sdata,
        struct ieee80211_if_managed *ifmgd = &sdata->u.mgd;
        u8 frame_buf[IEEE80211_DEAUTH_FRAME_LEN];
        bool tx = !req->local_state_change;
+       bool sent_frame = false;
 
        mutex_lock(&ifmgd->mtx);
 
-       if (ifmgd->auth_data) {
-               ieee80211_destroy_auth_data(sdata, false);
-               mutex_unlock(&ifmgd->mtx);
-               return 0;
-       }
-
        sdata_info(sdata,
                   "deauthenticating from %pM by local choice (reason=%d)\n",
                   req->bssid, req->reason_code);
 
-       if (ifmgd->associated &&
-           ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
-               ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
-                                      req->reason_code, tx, frame_buf);
-       } else {
+       if (ifmgd->auth_data) {
                drv_mgd_prepare_tx(sdata->local, sdata);
                ieee80211_send_deauth_disassoc(sdata, req->bssid,
                                               IEEE80211_STYPE_DEAUTH,
                                               req->reason_code, tx,
                                               frame_buf);
+               ieee80211_destroy_auth_data(sdata, false);
+               mutex_unlock(&ifmgd->mtx);
+
+               sent_frame = tx;
+               goto out;
        }
 
+       if (ifmgd->associated &&
+           ether_addr_equal(ifmgd->associated->bssid, req->bssid)) {
+               ieee80211_set_disassoc(sdata, IEEE80211_STYPE_DEAUTH,
+                                      req->reason_code, tx, frame_buf);
+               sent_frame = tx;
+       }
        mutex_unlock(&ifmgd->mtx);
 
-       __cfg80211_send_deauth(sdata->dev, frame_buf,
-                              IEEE80211_DEAUTH_FRAME_LEN);
-
+ out:
        mutex_lock(&sdata->local->mtx);
        ieee80211_recalc_idle(sdata->local);
        mutex_unlock(&sdata->local->mtx);
 
+       if (sent_frame)
+               __cfg80211_send_deauth(sdata->dev, frame_buf,
+                                      IEEE80211_DEAUTH_FRAME_LEN);
+
        return 0;
 }
 
index c349f3aaf59ed0d62c497634dfae5885aa5cc856..5abddfe3e1014f7bf19b4efaf5d19d6d20303467 100644 (file)
@@ -204,9 +204,9 @@ void ieee80211_handle_roc_started(struct ieee80211_roc_work *roc)
                        roc->frame = NULL;
                }
        } else {
-               cfg80211_ready_on_channel(&roc->sdata->wdev, (unsigned long)roc,
-                                         roc->chan, roc->chan_type,
-                                         roc->req_duration, GFP_KERNEL);
+               cfg80211_ready_on_channel(&roc->sdata->wdev, roc->cookie,
+                                         roc->chan, roc->req_duration,
+                                         GFP_KERNEL);
        }
 
        roc->notified = true;
@@ -283,8 +283,7 @@ void ieee80211_start_next_roc(struct ieee80211_local *local)
                if (!duration)
                        duration = 10;
 
-               ret = drv_remain_on_channel(local, roc->chan,
-                                           roc->chan_type,
+               ret = drv_remain_on_channel(local, roc->sdata, roc->chan,
                                            duration);
 
                roc->started = true;
@@ -320,8 +319,7 @@ void ieee80211_roc_notify_destroy(struct ieee80211_roc_work *roc)
 
        if (!roc->mgmt_tx_cookie)
                cfg80211_remain_on_channel_expired(&roc->sdata->wdev,
-                                                  (unsigned long)roc,
-                                                  roc->chan, roc->chan_type,
+                                                  roc->cookie, roc->chan,
                                                   GFP_KERNEL);
 
        list_for_each_entry_safe(dep, tmp, &roc->dependents, list)
@@ -360,7 +358,6 @@ void ieee80211_sw_roc_work(struct work_struct *work)
                ieee80211_recalc_idle(local);
 
                local->tmp_channel = roc->chan;
-               local->tmp_channel_type = roc->chan_type;
                ieee80211_hw_config(local, 0);
 
                /* tell userspace or send frame */
index 9f404ac901ab60cb3d9ee69e0eb9d7516e8484f5..79a48f37d4092b27a88b8fa136f15a51812365f2 100644 (file)
@@ -33,6 +33,7 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
        struct ieee80211_local *local = hw_to_local(hw);
        struct ieee80211_sub_if_data *sdata;
        struct sta_info *sta;
+       struct ieee80211_chanctx *ctx;
 
        if (!local->open_count)
                goto suspend;
@@ -135,14 +136,55 @@ int __ieee80211_suspend(struct ieee80211_hw *hw, struct cfg80211_wowlan *wowlan)
                ieee80211_bss_info_change_notify(sdata,
                        BSS_CHANGED_BEACON_ENABLED);
 
-               /* the interface is leaving the channel and is removed */
-               ieee80211_vif_release_channel(sdata);
+               if (sdata->vif.type == NL80211_IFTYPE_AP &&
+                   rcu_access_pointer(sdata->u.ap.beacon))
+                       drv_stop_ap(local, sdata);
+
+               if (local->use_chanctx) {
+                       struct ieee80211_chanctx_conf *conf;
+
+                       mutex_lock(&local->chanctx_mtx);
+                       conf = rcu_dereference_protected(
+                                       sdata->vif.chanctx_conf,
+                                       lockdep_is_held(&local->chanctx_mtx));
+                       if (conf) {
+                               ctx = container_of(conf,
+                                                  struct ieee80211_chanctx,
+                                                  conf);
+                               drv_unassign_vif_chanctx(local, sdata, ctx);
+                       }
+
+                       mutex_unlock(&local->chanctx_mtx);
+               }
                drv_remove_interface(local, sdata);
        }
 
        sdata = rtnl_dereference(local->monitor_sdata);
-       if (sdata)
+       if (sdata) {
+               if (local->use_chanctx) {
+                       struct ieee80211_chanctx_conf *conf;
+
+                       mutex_lock(&local->chanctx_mtx);
+                       conf = rcu_dereference_protected(
+                                       sdata->vif.chanctx_conf,
+                                       lockdep_is_held(&local->chanctx_mtx));
+                       if (conf) {
+                               ctx = container_of(conf,
+                                                  struct ieee80211_chanctx,
+                                                  conf);
+                               drv_unassign_vif_chanctx(local, sdata, ctx);
+                       }
+
+                       mutex_unlock(&local->chanctx_mtx);
+               }
+
                drv_remove_interface(local, sdata);
+       }
+
+       mutex_lock(&local->chanctx_mtx);
+       list_for_each_entry(ctx, &local->chanctx_list, list)
+               drv_remove_chanctx(local, ctx);
+       mutex_unlock(&local->chanctx_mtx);
 
        /* stop hardware - this must stop RX */
        if (local->open_count)
index 3313c117b322a928d17586c766c66bb698ca17bf..dd88381c53b7780dcae3a3b7e47ca0ca56a54474 100644 (file)
@@ -391,7 +391,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
                        return;
 
                /* if HT BSS, and we handle a data frame, also try HT rates */
-               if (txrc->bss_conf->channel_type == NL80211_CHAN_NO_HT)
+               if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_20_NOHT)
                        return;
 
                fc = hdr->frame_control;
@@ -408,8 +408,7 @@ static void rate_idx_match_mask(struct ieee80211_tx_rate *rate,
 
                alt_rate.flags |= IEEE80211_TX_RC_MCS;
 
-               if ((txrc->bss_conf->channel_type == NL80211_CHAN_HT40MINUS) ||
-                   (txrc->bss_conf->channel_type == NL80211_CHAN_HT40PLUS))
+               if (txrc->bss_conf->chandef.width == NL80211_CHAN_WIDTH_40)
                        alt_rate.flags |= IEEE80211_TX_RC_40_MHZ_WIDTH;
 
                if (rate_idx_match_mcs_mask(&alt_rate, mcs_mask)) {
index ec198ef6aa8af2a05ba84e3871a6ebf06c411089..301386dabf88da51f205d0961021e47cdbbb1ddf 100644 (file)
@@ -65,7 +65,7 @@ static inline void rate_control_rate_init(struct sta_info *sta)
                return;
        }
 
-       sband = local->hw.wiphy->bands[chanctx_conf->channel->band];
+       sband = local->hw.wiphy->bands[chanctx_conf->def.chan->band];
        rcu_read_unlock();
 
        ref->ops->rate_init(ref->priv, sband, ista, priv_sta);
index 8c1f1527d67162ff12365babe76084e6bd889cfb..825f33cf7bbc81834dca8e143674a0be31c74547 100644 (file)
@@ -40,6 +40,8 @@
 static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
                                           struct sk_buff *skb)
 {
+       struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
+
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS) {
                if (likely(skb->len > FCS_LEN))
                        __pskb_trim(skb, skb->len - FCS_LEN);
@@ -51,20 +53,25 @@ static struct sk_buff *remove_monitor_info(struct ieee80211_local *local,
                }
        }
 
+       if (status->vendor_radiotap_len)
+               __pskb_pull(skb, status->vendor_radiotap_len);
+
        return skb;
 }
 
-static inline int should_drop_frame(struct sk_buff *skb,
-                                   int present_fcs_len)
+static inline int should_drop_frame(struct sk_buff *skb, int present_fcs_len)
 {
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)skb->data;
+       struct ieee80211_hdr *hdr;
+
+       hdr = (void *)(skb->data + status->vendor_radiotap_len);
 
        if (status->flag & (RX_FLAG_FAILED_FCS_CRC |
                            RX_FLAG_FAILED_PLCP_CRC |
                            RX_FLAG_AMPDU_IS_ZEROLEN))
                return 1;
-       if (unlikely(skb->len < 16 + present_fcs_len))
+       if (unlikely(skb->len < 16 + present_fcs_len +
+                               status->vendor_radiotap_len))
                return 1;
        if (ieee80211_is_ctl(hdr->frame_control) &&
            !ieee80211_is_pspoll(hdr->frame_control) &&
@@ -74,32 +81,48 @@ static inline int should_drop_frame(struct sk_buff *skb,
 }
 
 static int
-ieee80211_rx_radiotap_len(struct ieee80211_local *local,
-                         struct ieee80211_rx_status *status)
+ieee80211_rx_radiotap_space(struct ieee80211_local *local,
+                           struct ieee80211_rx_status *status)
 {
        int len;
 
        /* always present fields */
        len = sizeof(struct ieee80211_radiotap_header) + 9;
 
-       if (status->flag & RX_FLAG_MACTIME_MPDU)
+       /* allocate extra bitmap */
+       if (status->vendor_radiotap_len)
+               len += 4;
+
+       if (ieee80211_have_rx_timestamp(status)) {
+               len = ALIGN(len, 8);
                len += 8;
+       }
        if (local->hw.flags & IEEE80211_HW_SIGNAL_DBM)
                len += 1;
 
-       if (len & 1) /* padding for RX_FLAGS if necessary */
-               len++;
+       /* padding for RX_FLAGS if necessary */
+       len = ALIGN(len, 2);
 
        if (status->flag & RX_FLAG_HT) /* HT info */
                len += 3;
 
        if (status->flag & RX_FLAG_AMPDU_DETAILS) {
-               /* padding */
-               while (len & 3)
-                       len++;
+               len = ALIGN(len, 4);
                len += 8;
        }
 
+       if (status->vendor_radiotap_len) {
+               if (WARN_ON_ONCE(status->vendor_radiotap_align == 0))
+                       status->vendor_radiotap_align = 1;
+               /* align standard part of vendor namespace */
+               len = ALIGN(len, 2);
+               /* allocate standard part of vendor namespace */
+               len += 6;
+               /* align vendor-defined part */
+               len = ALIGN(len, status->vendor_radiotap_align);
+               /* vendor-defined part is already in skb */
+       }
+
        return len;
 }
 
@@ -118,6 +141,11 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        struct ieee80211_radiotap_header *rthdr;
        unsigned char *pos;
        u16 rx_flags = 0;
+       int mpdulen;
+
+       mpdulen = skb->len;
+       if (!(has_fcs && (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)))
+               mpdulen += FCS_LEN;
 
        rthdr = (struct ieee80211_radiotap_header *)skb_push(skb, rtap_len);
        memset(rthdr, 0, rtap_len);
@@ -128,17 +156,30 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                            (1 << IEEE80211_RADIOTAP_CHANNEL) |
                            (1 << IEEE80211_RADIOTAP_ANTENNA) |
                            (1 << IEEE80211_RADIOTAP_RX_FLAGS));
-       rthdr->it_len = cpu_to_le16(rtap_len);
+       rthdr->it_len = cpu_to_le16(rtap_len + status->vendor_radiotap_len);
 
-       pos = (unsigned char *)(rthdr+1);
+       pos = (unsigned char *)(rthdr + 1);
+
+       if (status->vendor_radiotap_len) {
+               rthdr->it_present |=
+                       cpu_to_le32(BIT(IEEE80211_RADIOTAP_VENDOR_NAMESPACE)) |
+                       cpu_to_le32(BIT(IEEE80211_RADIOTAP_EXT));
+               put_unaligned_le32(status->vendor_radiotap_bitmap, pos);
+               pos += 4;
+       }
 
        /* the order of the following fields is important */
 
        /* IEEE80211_RADIOTAP_TSFT */
-       if (status->flag & RX_FLAG_MACTIME_MPDU) {
-               put_unaligned_le64(status->mactime, pos);
-               rthdr->it_present |=
-                       cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
+       if (ieee80211_have_rx_timestamp(status)) {
+               /* padding */
+               while ((pos - (u8 *)rthdr) & 7)
+                       *pos++ = 0;
+               put_unaligned_le64(
+                       ieee80211_calculate_rx_timestamp(local, status,
+                                                        mpdulen, 0),
+                       pos);
+               rthdr->it_present |= cpu_to_le32(1 << IEEE80211_RADIOTAP_TSFT);
                pos += 8;
        }
 
@@ -152,7 +193,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        pos++;
 
        /* IEEE80211_RADIOTAP_RATE */
-       if (!rate || status->flag & RX_FLAG_HT) {
+       if (!rate || status->flag & (RX_FLAG_HT | RX_FLAG_VHT)) {
                /*
                 * Without rate information don't add it. If we have,
                 * MCS information is a separate field in radiotap,
@@ -172,7 +213,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        if (status->band == IEEE80211_BAND_5GHZ)
                put_unaligned_le16(IEEE80211_CHAN_OFDM | IEEE80211_CHAN_5GHZ,
                                   pos);
-       else if (status->flag & RX_FLAG_HT)
+       else if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
                put_unaligned_le16(IEEE80211_CHAN_DYN | IEEE80211_CHAN_2GHZ,
                                   pos);
        else if (rate && rate->flags & IEEE80211_RATE_ERP_G)
@@ -205,7 +246,7 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
        /* IEEE80211_RADIOTAP_RX_FLAGS */
        /* ensure 2 byte alignment for the 2 byte field as required */
        if ((pos - (u8 *)rthdr) & 1)
-               pos++;
+               *pos++ = 0;
        if (status->flag & RX_FLAG_FAILED_PLCP_CRC)
                rx_flags |= IEEE80211_RADIOTAP_F_RX_BADPLCP;
        put_unaligned_le16(rx_flags, pos);
@@ -255,6 +296,21 @@ ieee80211_add_rx_radiotap_header(struct ieee80211_local *local,
                        *pos++ = 0;
                *pos++ = 0;
        }
+
+       if (status->vendor_radiotap_len) {
+               /* ensure 2 byte alignment for the vendor field as required */
+               if ((pos - (u8 *)rthdr) & 1)
+                       *pos++ = 0;
+               *pos++ = status->vendor_radiotap_oui[0];
+               *pos++ = status->vendor_radiotap_oui[1];
+               *pos++ = status->vendor_radiotap_oui[2];
+               *pos++ = status->vendor_radiotap_subns;
+               put_unaligned_le16(status->vendor_radiotap_len, pos);
+               pos += 2;
+               /* align the actual payload as requested */
+               while ((pos - (u8 *)rthdr) & (status->vendor_radiotap_align - 1))
+                       *pos++ = 0;
+       }
 }
 
 /*
@@ -283,13 +339,13 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
         */
 
        /* room for the radiotap header based on driver features */
-       needed_headroom = ieee80211_rx_radiotap_len(local, status);
+       needed_headroom = ieee80211_rx_radiotap_space(local, status);
 
        if (local->hw.flags & IEEE80211_HW_RX_INCLUDES_FCS)
                present_fcs_len = FCS_LEN;
 
-       /* make sure hdr->frame_control is on the linear part */
-       if (!pskb_may_pull(origskb, 2)) {
+       /* ensure hdr->frame_control and vendor radiotap data are in skb head */
+       if (!pskb_may_pull(origskb, 2 + status->vendor_radiotap_len)) {
                dev_kfree_skb(origskb);
                return NULL;
        }
@@ -374,7 +430,6 @@ ieee80211_rx_monitor(struct ieee80211_local *local, struct sk_buff *origskb,
        return origskb;
 }
 
-
 static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
@@ -403,10 +458,10 @@ static void ieee80211_parse_qos(struct ieee80211_rx_data *rx)
                 *
                 * We also use that counter for non-QoS STAs.
                 */
-               seqno_idx = NUM_RX_DATA_QUEUES;
+               seqno_idx = IEEE80211_NUM_TIDS;
                security_idx = 0;
                if (ieee80211_is_mgmt(hdr->frame_control))
-                       security_idx = NUM_RX_DATA_QUEUES;
+                       security_idx = IEEE80211_NUM_TIDS;
                tid = 0;
        }
 
@@ -481,8 +536,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        struct ieee80211_mgmt *hdr = (struct ieee80211_mgmt *) skb->data;
        struct ieee80211_mmie *mmie;
 
-       if (skb->len < 24 + sizeof(*mmie) ||
-           !is_multicast_ether_addr(hdr->da))
+       if (skb->len < 24 + sizeof(*mmie) || !is_multicast_ether_addr(hdr->da))
                return -1;
 
        if (!ieee80211_is_robust_mgmt_frame((struct ieee80211_hdr *) hdr))
@@ -497,9 +551,7 @@ static int ieee80211_get_mmie_keyidx(struct sk_buff *skb)
        return le16_to_cpu(mmie->key_id);
 }
 
-
-static ieee80211_rx_result
-ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
+static ieee80211_rx_result ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        char *dev_addr = rx->sdata->vif.addr;
@@ -507,7 +559,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
        if (ieee80211_is_data(hdr->frame_control)) {
                if (is_multicast_ether_addr(hdr->addr1)) {
                        if (ieee80211_has_tods(hdr->frame_control) ||
-                               !ieee80211_has_fromds(hdr->frame_control))
+                           !ieee80211_has_fromds(hdr->frame_control))
                                return RX_DROP_MONITOR;
                        if (ether_addr_equal(hdr->addr3, dev_addr))
                                return RX_DROP_MONITOR;
@@ -539,7 +591,7 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
                        mgmt = (struct ieee80211_mgmt *)hdr;
                        category = mgmt->u.action.category;
                        if (category != WLAN_CATEGORY_MESH_ACTION &&
-                               category != WLAN_CATEGORY_SELF_PROTECTED)
+                           category != WLAN_CATEGORY_SELF_PROTECTED)
                                return RX_DROP_MONITOR;
                        return RX_CONTINUE;
                }
@@ -551,7 +603,6 @@ ieee80211_rx_mesh_check(struct ieee80211_rx_data *rx)
                        return RX_CONTINUE;
 
                return RX_DROP_MONITOR;
-
        }
 
        return RX_CONTINUE;
@@ -575,7 +626,6 @@ static inline u16 seq_sub(u16 sq1, u16 sq2)
        return (sq1 - sq2) & SEQ_MASK;
 }
 
-
 static void ieee80211_release_reorder_frame(struct ieee80211_sub_if_data *sdata,
                                            struct tid_ampdu_rx *tid_agg_rx,
                                            int index)
@@ -1291,17 +1341,22 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
 
        /*
         * Update last_rx only for IBSS packets which are for the current
-        * BSSID to avoid keeping the current IBSS network alive in cases
-        * where other STAs start using different BSSID.
+        * BSSID and for station already AUTHORIZED to avoid keeping the
+        * current IBSS network alive in cases where other STAs start
+        * using different BSSID. This will also give the station another
+        * chance to restart the authentication/authorization in case
+        * something went wrong the first time.
         */
        if (rx->sdata->vif.type == NL80211_IFTYPE_ADHOC) {
                u8 *bssid = ieee80211_get_bssid(hdr, rx->skb->len,
                                                NL80211_IFTYPE_ADHOC);
-               if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid)) {
+               if (ether_addr_equal(bssid, rx->sdata->u.ibss.bssid) &&
+                   test_sta_flag(sta, WLAN_STA_AUTHORIZED)) {
                        sta->last_rx = jiffies;
                        if (ieee80211_is_data(hdr->frame_control)) {
                                sta->last_rx_rate_idx = status->rate_idx;
                                sta->last_rx_rate_flag = status->flag;
+                               sta->last_rx_rate_vht_nss = status->vht_nss;
                        }
                }
        } else if (!is_multicast_ether_addr(hdr->addr1)) {
@@ -1313,6 +1368,7 @@ ieee80211_rx_h_sta_process(struct ieee80211_rx_data *rx)
                if (ieee80211_is_data(hdr->frame_control)) {
                        sta->last_rx_rate_idx = status->rate_idx;
                        sta->last_rx_rate_flag = status->flag;
+                       sta->last_rx_rate_vht_nss = status->vht_nss;
                }
        }
 
@@ -1585,18 +1641,15 @@ ieee80211_rx_h_defragment(struct ieee80211_rx_data *rx)
        return RX_CONTINUE;
 }
 
-static int
-ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
+static int ieee80211_802_1x_port_control(struct ieee80211_rx_data *rx)
 {
-       if (unlikely(!rx->sta ||
-           !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
+       if (unlikely(!rx->sta || !test_sta_flag(rx->sta, WLAN_STA_AUTHORIZED)))
                return -EACCES;
 
        return 0;
 }
 
-static int
-ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
+static int ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
 {
        struct sk_buff *skb = rx->skb;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(skb);
@@ -1618,8 +1671,7 @@ ieee80211_drop_unencrypted(struct ieee80211_rx_data *rx, __le16 fc)
        return 0;
 }
 
-static int
-ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
+static int ieee80211_drop_unencrypted_mgmt(struct ieee80211_rx_data *rx)
 {
        struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)rx->skb->data;
        struct ieee80211_rx_status *status = IEEE80211_SKB_RXCB(rx->skb);
@@ -2003,7 +2055,7 @@ ieee80211_rx_h_mesh_fwding(struct ieee80211_rx_data *rx)
        } else {
                /* unable to resolve next hop */
                mesh_path_error_tx(ifmsh->mshcfg.element_ttl, fwd_hdr->addr3,
-                                   0, reason, fwd_hdr->addr2, sdata);
+                                  0, reason, fwd_hdr->addr2, sdata);
                IEEE80211_IFSTA_MESH_CTR_INC(ifmsh, dropped_frames_no_route);
                kfree_skb(fwd_skb);
                return RX_DROP_MONITOR;
@@ -2212,7 +2264,7 @@ ieee80211_rx_h_mgmt_check(struct ieee80211_rx_data *rx)
 
                cfg80211_report_obss_beacon(rx->local->hw.wiphy,
                                            rx->skb->data, rx->skb->len,
-                                           status->freq, sig, GFP_ATOMIC);
+                                           status->freq, sig);
                rx->flags |= IEEE80211_RX_BEACON_REPORTED;
        }
 
@@ -2412,7 +2464,7 @@ ieee80211_rx_h_action(struct ieee80211_rx_data *rx)
                if (!ieee80211_vif_is_mesh(&sdata->vif))
                        break;
                if (mesh_action_is_path_sel(mgmt) &&
-                 (!mesh_path_sel_is_hwmp(sdata)))
+                   !mesh_path_sel_is_hwmp(sdata))
                        break;
                goto queue;
        }
@@ -2468,7 +2520,6 @@ ieee80211_rx_h_userspace_mgmt(struct ieee80211_rx_data *rx)
                return RX_QUEUED;
        }
 
-
        return RX_CONTINUE;
 }
 
@@ -2598,7 +2649,7 @@ static void ieee80211_rx_cooked_monitor(struct ieee80211_rx_data *rx,
                goto out_free_skb;
 
        /* room for the radiotap header based on driver features */
-       needed_headroom = ieee80211_rx_radiotap_len(local, status);
+       needed_headroom = ieee80211_rx_radiotap_space(local, status);
 
        if (skb_headroom(skb) < needed_headroom &&
            pskb_expand_head(skb, needed_headroom, 0, GFP_ATOMIC))
@@ -2661,7 +2712,8 @@ static void ieee80211_rx_handlers_result(struct ieee80211_rx_data *rx,
                status = IEEE80211_SKB_RXCB((rx->skb));
 
                sband = rx->local->hw.wiphy->bands[status->band];
-               if (!(status->flag & RX_FLAG_HT))
+               if (!(status->flag & RX_FLAG_HT) &&
+                   !(status->flag & RX_FLAG_VHT))
                        rate = &sband->bitrates[status->rate_idx];
 
                ieee80211_rx_cooked_monitor(rx, rate);
@@ -2828,8 +2880,8 @@ static int prepare_for_handlers(struct ieee80211_rx_data *rx,
                        status->rx_flags &= ~IEEE80211_RX_RA_MATCH;
                } else if (!rx->sta) {
                        int rate_idx;
-                       if (status->flag & RX_FLAG_HT)
-                               rate_idx = 0; /* TODO: HT rates */
+                       if (status->flag & (RX_FLAG_HT | RX_FLAG_VHT))
+                               rate_idx = 0; /* TODO: HT/VHT rates */
                        else
                                rate_idx = status->rate_idx;
                        ieee80211_ibss_rx_no_sta(sdata, bssid, hdr->addr2,
@@ -3105,6 +3157,13 @@ void ieee80211_rx(struct ieee80211_hw *hw, struct sk_buff *skb)
                                 status->rate_idx,
                                 status->rate_idx))
                                goto drop;
+               } else if (status->flag & RX_FLAG_VHT) {
+                       if (WARN_ONCE(status->rate_idx > 9 ||
+                                     !status->vht_nss ||
+                                     status->vht_nss > 8,
+                                     "Rate marked as a VHT rate but data is invalid: MCS: %d, NSS: %d\n",
+                                     status->rate_idx, status->vht_nss))
+                               goto drop;
                } else {
                        if (WARN_ON(status->rate_idx >= sband->n_bitrates))
                                goto drop;
index 8e9bb168b73bff0f1c50c44d5e835ffba4696ae1..f3340279aba3c1bf14616cebe90fb7ce17a6837d 100644 (file)
@@ -174,7 +174,6 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
        u8 *elements;
        struct ieee80211_channel *channel;
        size_t baselen;
-       int freq;
        bool beacon;
        struct ieee802_11_elems elems;
 
@@ -209,13 +208,7 @@ void ieee80211_scan_rx(struct ieee80211_local *local, struct sk_buff *skb)
 
        ieee802_11_parse_elems(elements, skb->len - baselen, &elems);
 
-       if (elems.ds_params && elems.ds_params_len == 1)
-               freq = ieee80211_channel_to_frequency(elems.ds_params[0],
-                                                     rx_status->band);
-       else
-               freq = rx_status->freq;
-
-       channel = ieee80211_get_channel(local->hw.wiphy, freq);
+       channel = ieee80211_get_channel(local->hw.wiphy, rx_status->freq);
 
        if (!channel || channel->flags & IEEE80211_CHAN_DISABLED)
                return;
index e9d57689c05fb076e4f9bfe293a8b6d98929a154..f3e502502fee27374dc4c183733cbcc95217aed5 100644 (file)
@@ -142,7 +142,7 @@ static void free_sta_work(struct work_struct *wk)
         * drivers have to handle aggregation stop being requested, followed
         * directly by station destruction.
         */
-       for (i = 0; i < STA_TID_NUM; i++) {
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
                tid_tx = rcu_dereference_raw(sta->ampdu_mlme.tid_tx[i]);
                if (!tid_tx)
                        continue;
@@ -330,7 +330,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                return NULL;
        }
 
-       for (i = 0; i < STA_TID_NUM; i++) {
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++) {
                /*
                 * timer_to_tid must be initialized with identity mapping
                 * to enable session_timer's data differentiation. See
@@ -343,7 +343,7 @@ struct sta_info *sta_info_alloc(struct ieee80211_sub_if_data *sdata,
                skb_queue_head_init(&sta->tx_filtered[i]);
        }
 
-       for (i = 0; i < NUM_RX_DATA_QUEUES; i++)
+       for (i = 0; i < IEEE80211_NUM_TIDS; i++)
                sta->last_seq_ctrl[i] = cpu_to_le16(USHRT_MAX);
 
        sta_dbg(sdata, "Allocated STA %pM\n", sta->sta.addr);
@@ -986,7 +986,7 @@ void ieee80211_sta_ps_deliver_wakeup(struct sta_info *sta)
 
        clear_sta_flag(sta, WLAN_STA_SP);
 
-       BUILD_BUG_ON(BITS_TO_LONGS(STA_TID_NUM) > 1);
+       BUILD_BUG_ON(BITS_TO_LONGS(IEEE80211_NUM_TIDS) > 1);
        sta->driver_buffered_tids = 0;
 
        if (!(local->hw.flags & IEEE80211_HW_AP_LINK_PS))
@@ -1092,7 +1092,7 @@ static void ieee80211_send_null_response(struct ieee80211_sub_if_data *sdata,
                return;
        }
 
-       ieee80211_xmit(sdata, skb, chanctx_conf->channel->band);
+       ieee80211_xmit(sdata, skb, chanctx_conf->def.chan->band);
        rcu_read_unlock();
 }
 
@@ -1374,7 +1374,7 @@ void ieee80211_sta_set_buffered(struct ieee80211_sta *pubsta,
 {
        struct sta_info *sta = container_of(pubsta, struct sta_info, sta);
 
-       if (WARN_ON(tid >= STA_TID_NUM))
+       if (WARN_ON(tid >= IEEE80211_NUM_TIDS))
                return;
 
        if (buffered)
index c88f161f81185a678335fe3df6201fb8e64c8d80..6835cea4e40248b43bdfdcbb0a7413271b5e4b95 100644 (file)
@@ -80,7 +80,6 @@ enum ieee80211_sta_info_flags {
        WLAN_STA_TOFFSET_KNOWN,
 };
 
-#define STA_TID_NUM 16
 #define ADDBA_RESP_INTERVAL HZ
 #define HT_AGG_MAX_RETRIES             15
 #define HT_AGG_BURST_RETRIES           3
@@ -197,15 +196,15 @@ struct tid_ampdu_rx {
 struct sta_ampdu_mlme {
        struct mutex mtx;
        /* rx */
-       struct tid_ampdu_rx __rcu *tid_rx[STA_TID_NUM];
-       unsigned long tid_rx_timer_expired[BITS_TO_LONGS(STA_TID_NUM)];
-       unsigned long tid_rx_stop_requested[BITS_TO_LONGS(STA_TID_NUM)];
+       struct tid_ampdu_rx __rcu *tid_rx[IEEE80211_NUM_TIDS];
+       unsigned long tid_rx_timer_expired[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
+       unsigned long tid_rx_stop_requested[BITS_TO_LONGS(IEEE80211_NUM_TIDS)];
        /* tx */
        struct work_struct work;
-       struct tid_ampdu_tx __rcu *tid_tx[STA_TID_NUM];
-       struct tid_ampdu_tx *tid_start_tx[STA_TID_NUM];
-       unsigned long last_addba_req_time[STA_TID_NUM];
-       u8 addba_req_num[STA_TID_NUM];
+       struct tid_ampdu_tx __rcu *tid_tx[IEEE80211_NUM_TIDS];
+       struct tid_ampdu_tx *tid_start_tx[IEEE80211_NUM_TIDS];
+       unsigned long last_addba_req_time[IEEE80211_NUM_TIDS];
+       u8 addba_req_num[IEEE80211_NUM_TIDS];
        u8 dialog_token_allocator;
 };
 
@@ -228,6 +227,7 @@ struct sta_ampdu_mlme {
  *     "the" transmit rate
  * @last_rx_rate_idx: rx status rate index of the last data packet
  * @last_rx_rate_flag: rx status flag of the last data packet
+ * @last_rx_rate_vht_nss: rx status nss of last data packet
  * @lock: used for locking all fields that require locking, see comments
  *     in the header file.
  * @drv_unblock_wk: used for driver PS unblocking
@@ -273,7 +273,7 @@ struct sta_ampdu_mlme {
  * @t_offset: timing offset relative to this host
  * @t_offset_setpoint: reference timing offset of this sta to be used when
  *     calculating clockdrift
- * @ch_type: peer's channel type
+ * @ch_width: peer's channel width
  * @debugfs: debug filesystem info
  * @dead: set to true when sta is unlinked
  * @uploaded: set to true when sta is uploaded to the driver
@@ -330,7 +330,7 @@ struct sta_info {
        int last_signal;
        struct ewma avg_signal;
        /* Plus 1 for non-QoS frames */
-       __le16 last_seq_ctrl[NUM_RX_DATA_QUEUES + 1];
+       __le16 last_seq_ctrl[IEEE80211_NUM_TIDS + 1];
 
        /* Updated from TX status path only, no locking requirements */
        unsigned long tx_filtered_count;
@@ -344,14 +344,15 @@ struct sta_info {
        unsigned long tx_fragments;
        struct ieee80211_tx_rate last_tx_rate;
        int last_rx_rate_idx;
-       int last_rx_rate_flag;
+       u32 last_rx_rate_flag;
+       u8 last_rx_rate_vht_nss;
        u16 tid_seq[IEEE80211_QOS_CTL_TID_MASK + 1];
 
        /*
         * Aggregation information, locked with lock.
         */
        struct sta_ampdu_mlme ampdu_mlme;
-       u8 timer_to_tid[STA_TID_NUM];
+       u8 timer_to_tid[IEEE80211_NUM_TIDS];
 
 #ifdef CONFIG_MAC80211_MESH
        /*
@@ -369,7 +370,7 @@ struct sta_info {
        struct timer_list plink_timer;
        s64 t_offset;
        s64 t_offset_setpoint;
-       enum nl80211_channel_type ch_type;
+       enum nl80211_chan_width ch_width;
 #endif
 
 #ifdef CONFIG_MAC80211_DEBUGFS
index 248247877eb60adbbac7d2f6316a67a9dbcbabea..ab63237107c8ac646b2bb414121c9d0c4593e766 100644 (file)
@@ -325,6 +325,75 @@ static void ieee80211_add_tx_radiotap_header(struct ieee80211_supported_band
 
 }
 
+static void ieee80211_report_used_skb(struct ieee80211_local *local,
+                                     struct sk_buff *skb, bool dropped)
+{
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_hdr *hdr = (void *)skb->data;
+       bool acked = info->flags & IEEE80211_TX_STAT_ACK;
+
+       if (dropped)
+               acked = false;
+
+       if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
+               struct ieee80211_sub_if_data *sdata = NULL;
+               struct ieee80211_sub_if_data *iter_sdata;
+               u64 cookie = (unsigned long)skb;
+
+               rcu_read_lock();
+
+               if (skb->dev) {
+                       list_for_each_entry_rcu(iter_sdata, &local->interfaces,
+                                               list) {
+                               if (!iter_sdata->dev)
+                                       continue;
+
+                               if (skb->dev == iter_sdata->dev) {
+                                       sdata = iter_sdata;
+                                       break;
+                               }
+                       }
+               } else {
+                       sdata = rcu_dereference(local->p2p_sdata);
+               }
+
+               if (!sdata)
+                       skb->dev = NULL;
+               else if (ieee80211_is_nullfunc(hdr->frame_control) ||
+                        ieee80211_is_qos_nullfunc(hdr->frame_control)) {
+                       cfg80211_probe_status(sdata->dev, hdr->addr1,
+                                             cookie, acked, GFP_ATOMIC);
+               } else {
+                       cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
+                                               skb->len, acked, GFP_ATOMIC);
+               }
+
+               rcu_read_unlock();
+       }
+
+       if (unlikely(info->ack_frame_id)) {
+               struct sk_buff *ack_skb;
+               unsigned long flags;
+
+               spin_lock_irqsave(&local->ack_status_lock, flags);
+               ack_skb = idr_find(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               if (ack_skb)
+                       idr_remove(&local->ack_status_frames,
+                                  info->ack_frame_id);
+               spin_unlock_irqrestore(&local->ack_status_lock, flags);
+
+               if (ack_skb) {
+                       if (!dropped) {
+                               /* consumes ack_skb */
+                               skb_complete_wifi_ack(ack_skb, acked);
+                       } else {
+                               dev_kfree_skb_any(ack_skb);
+                       }
+               }
+       }
+}
+
 /*
  * Use a static threshold for now, best value to be determined
  * by testing ...
@@ -516,62 +585,7 @@ void ieee80211_tx_status(struct ieee80211_hw *hw, struct sk_buff *skb)
                                        msecs_to_jiffies(10));
        }
 
-       if (info->flags & IEEE80211_TX_INTFL_NL80211_FRAME_TX) {
-               u64 cookie = (unsigned long)skb;
-               bool found = false;
-
-               acked = info->flags & IEEE80211_TX_STAT_ACK;
-
-               rcu_read_lock();
-
-               list_for_each_entry_rcu(sdata, &local->interfaces, list) {
-                       if (!sdata->dev)
-                               continue;
-
-                       if (skb->dev != sdata->dev)
-                               continue;
-
-                       found = true;
-                       break;
-               }
-
-               if (!skb->dev) {
-                       sdata = rcu_dereference(local->p2p_sdata);
-                       if (sdata)
-                               found = true;
-               }
-
-               if (!found)
-                       skb->dev = NULL;
-               else if (ieee80211_is_nullfunc(hdr->frame_control) ||
-                        ieee80211_is_qos_nullfunc(hdr->frame_control)) {
-                       cfg80211_probe_status(sdata->dev, hdr->addr1,
-                                             cookie, acked, GFP_ATOMIC);
-               } else {
-                       cfg80211_mgmt_tx_status(&sdata->wdev, cookie, skb->data,
-                                               skb->len, acked, GFP_ATOMIC);
-               }
-
-               rcu_read_unlock();
-       }
-
-       if (unlikely(info->ack_frame_id)) {
-               struct sk_buff *ack_skb;
-               unsigned long flags;
-
-               spin_lock_irqsave(&local->ack_status_lock, flags);
-               ack_skb = idr_find(&local->ack_status_frames,
-                                  info->ack_frame_id);
-               if (ack_skb)
-                       idr_remove(&local->ack_status_frames,
-                                  info->ack_frame_id);
-               spin_unlock_irqrestore(&local->ack_status_lock, flags);
-
-               /* consumes ack_skb */
-               if (ack_skb)
-                       skb_complete_wifi_ack(ack_skb,
-                               info->flags & IEEE80211_TX_STAT_ACK);
-       }
+       ieee80211_report_used_skb(local, skb, false);
 
        /* this was a transmitted frame, but now we want to reuse it */
        skb_orphan(skb);
@@ -647,25 +661,8 @@ EXPORT_SYMBOL(ieee80211_report_low_ack);
 void ieee80211_free_txskb(struct ieee80211_hw *hw, struct sk_buff *skb)
 {
        struct ieee80211_local *local = hw_to_local(hw);
-       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
-
-       if (unlikely(info->ack_frame_id)) {
-               struct sk_buff *ack_skb;
-               unsigned long flags;
-
-               spin_lock_irqsave(&local->ack_status_lock, flags);
-               ack_skb = idr_find(&local->ack_status_frames,
-                                  info->ack_frame_id);
-               if (ack_skb)
-                       idr_remove(&local->ack_status_frames,
-                                  info->ack_frame_id);
-               spin_unlock_irqrestore(&local->ack_status_lock, flags);
-
-               /* consumes ack_skb */
-               if (ack_skb)
-                       dev_kfree_skb_any(ack_skb);
-       }
 
+       ieee80211_report_used_skb(local, skb, true);
        dev_kfree_skb_any(skb);
 }
 EXPORT_SYMBOL(ieee80211_free_txskb);
index 0638541b625f155d0299998a8edbd457858f36e0..a8270b441a6f93249e095c74be849bdf9ce39f9b 100644 (file)
 #define VIF_PR_FMT     " vif:%s(%d%s)"
 #define VIF_PR_ARG     __get_str(vif_name), __entry->vif_type, __entry->p2p ? "/p2p" : ""
 
-#define CHANCTX_ENTRY  __field(int, freq)                                      \
-                       __field(int, chantype)                                  \
+#define CHANCTX_ENTRY  __field(u32, control_freq)                              \
+                       __field(u32, chan_width)                                \
+                       __field(u32, center_freq1)                              \
+                       __field(u32, center_freq2)                              \
                        __field(u8, rx_chains_static)                           \
                        __field(u8, rx_chains_dynamic)
-#define CHANCTX_ASSIGN __entry->freq = ctx->conf.channel->center_freq;         \
-                       __entry->chantype = ctx->conf.channel_type;             \
+#define CHANCTX_ASSIGN __entry->control_freq = ctx->conf.def.chan->center_freq;\
+                       __entry->chan_width = ctx->conf.def.width;              \
+                       __entry->center_freq1 = ctx->conf.def.center_freq1;     \
+                       __entry->center_freq2 = ctx->conf.def.center_freq2;     \
                        __entry->rx_chains_static = ctx->conf.rx_chains_static; \
                        __entry->rx_chains_dynamic = ctx->conf.rx_chains_dynamic
-#define CHANCTX_PR_FMT " freq:%d MHz chantype:%d chains:%d/%d"
-#define CHANCTX_PR_ARG __entry->freq, __entry->chantype,                       \
+#define CHANCTX_PR_FMT " control:%d MHz width:%d center: %d/%d MHz chains:%d/%d"
+#define CHANCTX_PR_ARG __entry->control_freq, __entry->chan_width,             \
+                       __entry->center_freq1, __entry->center_freq2,           \
                        __entry->rx_chains_static, __entry->rx_chains_dynamic
 
 
@@ -334,7 +339,8 @@ TRACE_EVENT(drv_bss_info_changed,
                __field(u16, ht_operation_mode)
                __field(s32, cqm_rssi_thold);
                __field(s32, cqm_rssi_hyst);
-               __field(u32, channel_type);
+               __field(u32, channel_width);
+               __field(u32, channel_cfreq1);
                __dynamic_array(u32, arp_addr_list, info->arp_addr_cnt);
                __field(bool, arp_filter_enabled);
                __field(bool, qos);
@@ -342,6 +348,9 @@ TRACE_EVENT(drv_bss_info_changed,
                __field(bool, ps);
                __dynamic_array(u8, ssid, info->ssid_len);
                __field(bool, hidden_ssid);
+               __field(int, txpower)
+               __field(u8, p2p_ctwindow)
+               __field(bool, p2p_oppps)
        ),
 
        TP_fast_assign(
@@ -367,7 +376,8 @@ TRACE_EVENT(drv_bss_info_changed,
                __entry->ht_operation_mode = info->ht_operation_mode;
                __entry->cqm_rssi_thold = info->cqm_rssi_thold;
                __entry->cqm_rssi_hyst = info->cqm_rssi_hyst;
-               __entry->channel_type = info->channel_type;
+               __entry->channel_width = info->chandef.width;
+               __entry->channel_cfreq1 = info->chandef.center_freq1;
                memcpy(__get_dynamic_array(arp_addr_list), info->arp_addr_list,
                       sizeof(u32) * info->arp_addr_cnt);
                __entry->arp_filter_enabled = info->arp_filter_enabled;
@@ -376,6 +386,9 @@ TRACE_EVENT(drv_bss_info_changed,
                __entry->ps = info->ps;
                memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
                __entry->hidden_ssid = info->hidden_ssid;
+               __entry->txpower = info->txpower;
+               __entry->p2p_ctwindow = info->p2p_ctwindow;
+               __entry->p2p_oppps = info->p2p_oppps;
        ),
 
        TP_printk(
@@ -1013,28 +1026,31 @@ TRACE_EVENT(drv_get_antenna,
 );
 
 TRACE_EVENT(drv_remain_on_channel,
-       TP_PROTO(struct ieee80211_local *local, struct ieee80211_channel *chan,
-                enum nl80211_channel_type chantype, unsigned int duration),
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_channel *chan,
+                unsigned int duration),
 
-       TP_ARGS(local, chan, chantype, duration),
+       TP_ARGS(local, sdata, chan, duration),
 
        TP_STRUCT__entry(
                LOCAL_ENTRY
+               VIF_ENTRY
                __field(int, center_freq)
-               __field(int, channel_type)
                __field(unsigned int, duration)
        ),
 
        TP_fast_assign(
                LOCAL_ASSIGN;
+               VIF_ASSIGN;
                __entry->center_freq = chan->center_freq;
-               __entry->channel_type = chantype;
                __entry->duration = duration;
        ),
 
        TP_printk(
-               LOCAL_PR_FMT " freq:%dMHz duration:%dms",
-               LOCAL_PR_ARG, __entry->center_freq, __entry->duration
+               LOCAL_PR_FMT  VIF_PR_FMT " freq:%dMHz duration:%dms",
+               LOCAL_PR_ARG, VIF_PR_ARG,
+               __entry->center_freq, __entry->duration
        )
 );
 
@@ -1043,34 +1059,6 @@ DEFINE_EVENT(local_only_evt, drv_cancel_remain_on_channel,
        TP_ARGS(local)
 );
 
-TRACE_EVENT(drv_offchannel_tx,
-       TP_PROTO(struct ieee80211_local *local, struct sk_buff *skb,
-                struct ieee80211_channel *chan,
-                enum nl80211_channel_type channel_type,
-                unsigned int wait),
-
-       TP_ARGS(local, skb, chan, channel_type, wait),
-
-       TP_STRUCT__entry(
-               LOCAL_ENTRY
-               __field(int, center_freq)
-               __field(int, channel_type)
-               __field(unsigned int, wait)
-       ),
-
-       TP_fast_assign(
-               LOCAL_ASSIGN;
-               __entry->center_freq = chan->center_freq;
-               __entry->channel_type = channel_type;
-               __entry->wait = wait;
-       ),
-
-       TP_printk(
-               LOCAL_PR_FMT " freq:%dMHz, wait:%dms",
-               LOCAL_PR_ARG, __entry->center_freq, __entry->wait
-       )
-);
-
 TRACE_EVENT(drv_set_ringparam,
        TP_PROTO(struct ieee80211_local *local, u32 tx, u32 rx),
 
@@ -1396,6 +1384,48 @@ DEFINE_EVENT(local_sdata_chanctx, drv_unassign_vif_chanctx,
        TP_ARGS(local, sdata, ctx)
 );
 
+TRACE_EVENT(drv_start_ap,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata,
+                struct ieee80211_bss_conf *info),
+
+       TP_ARGS(local, sdata, info),
+
+       TP_STRUCT__entry(
+               LOCAL_ENTRY
+               VIF_ENTRY
+               __field(u8, dtimper)
+               __field(u16, bcnint)
+               __dynamic_array(u8, ssid, info->ssid_len);
+               __field(bool, hidden_ssid);
+       ),
+
+       TP_fast_assign(
+               LOCAL_ASSIGN;
+               VIF_ASSIGN;
+               __entry->dtimper = info->dtim_period;
+               __entry->bcnint = info->beacon_int;
+               memcpy(__get_dynamic_array(ssid), info->ssid, info->ssid_len);
+               __entry->hidden_ssid = info->hidden_ssid;
+       ),
+
+       TP_printk(
+               LOCAL_PR_FMT  VIF_PR_FMT,
+               LOCAL_PR_ARG, VIF_PR_ARG
+       )
+);
+
+DEFINE_EVENT(local_sdata_evt, drv_stop_ap,
+       TP_PROTO(struct ieee80211_local *local,
+                struct ieee80211_sub_if_data *sdata),
+       TP_ARGS(local, sdata)
+);
+
+DEFINE_EVENT(local_only_evt, drv_restart_complete,
+       TP_PROTO(struct ieee80211_local *local),
+       TP_ARGS(local)
+);
+
 /*
  * Tracing for API calls that drivers call.
  */
index 6f1981816dc5a21f51b96089e3c3e75cce60a1f6..d287a4f2c01b469e4829562061097c8d25cba0a6 100644 (file)
@@ -1676,7 +1676,7 @@ netdev_tx_t ieee80211_monitor_start_xmit(struct sk_buff *skb,
        if (!chanctx_conf)
                goto fail_rcu;
 
-       chan = chanctx_conf->channel;
+       chan = chanctx_conf->def.chan;
 
        /*
         * Frame injection is not allowed if beaconing is not allowed
@@ -1779,7 +1779,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                chanctx_conf = rcu_dereference(ap_sdata->vif.chanctx_conf);
                if (!chanctx_conf)
                        goto fail_rcu;
-               band = chanctx_conf->channel->band;
+               band = chanctx_conf->def.chan->band;
                if (sta)
                        break;
                /* fall through */
@@ -1794,7 +1794,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
                if (!chanctx_conf)
                        goto fail_rcu;
-               band = chanctx_conf->channel->band;
+               band = chanctx_conf->def.chan->band;
                break;
        case NL80211_IFTYPE_WDS:
                fc |= cpu_to_le16(IEEE80211_FCTL_FROMDS | IEEE80211_FCTL_TODS);
@@ -1871,7 +1871,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
                if (!chanctx_conf)
                        goto fail_rcu;
-               band = chanctx_conf->channel->band;
+               band = chanctx_conf->def.chan->band;
                break;
 #endif
        case NL80211_IFTYPE_STATION:
@@ -1930,7 +1930,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
                if (!chanctx_conf)
                        goto fail_rcu;
-               band = chanctx_conf->channel->band;
+               band = chanctx_conf->def.chan->band;
                break;
        case NL80211_IFTYPE_ADHOC:
                /* DA SA BSSID */
@@ -1941,7 +1941,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
                if (!chanctx_conf)
                        goto fail_rcu;
-               band = chanctx_conf->channel->band;
+               band = chanctx_conf->def.chan->band;
                break;
        default:
                goto fail_rcu;
@@ -2089,6 +2089,7 @@ netdev_tx_t ieee80211_subif_start_xmit(struct sk_buff *skb,
                head_need = max_t(int, 0, head_need);
                if (ieee80211_skb_resize(sdata, skb, head_need, true)) {
                        ieee80211_free_txskb(&local->hw, skb);
+                       skb = NULL;
                        goto fail_rcu;
                }
        }
@@ -2193,7 +2194,7 @@ static bool ieee80211_tx_pending_skb(struct ieee80211_local *local,
                        return true;
                }
                result = ieee80211_tx(sdata, skb, true,
-                                     chanctx_conf->channel->band);
+                                     chanctx_conf->def.chan->band);
        } else {
                struct sk_buff_head skbs;
 
@@ -2457,7 +2458,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                *pos++ = WLAN_EID_SSID;
                *pos++ = 0x0;
 
-               band = chanctx_conf->channel->band;
+               band = chanctx_conf->def.chan->band;
 
                if (ieee80211_add_srates_ie(sdata, skb, true, band) ||
                    mesh_add_ds_params_ie(skb, sdata) ||
@@ -2476,7 +2477,7 @@ struct sk_buff *ieee80211_beacon_get_tim(struct ieee80211_hw *hw,
                goto out;
        }
 
-       band = chanctx_conf->channel->band;
+       band = chanctx_conf->def.chan->band;
 
        info = IEEE80211_SKB_CB(skb);
 
@@ -2756,7 +2757,7 @@ ieee80211_get_buffered_bc(struct ieee80211_hw *hw,
        info = IEEE80211_SKB_CB(skb);
 
        tx.flags |= IEEE80211_TX_PS_BUFFERED;
-       info->band = chanctx_conf->channel->band;
+       info->band = chanctx_conf->def.chan->band;
 
        if (invoke_tx_handlers(&tx))
                skb = NULL;
index acbb8c9bae2a352455bbe7de37fa970ceb819bc1..08132ff9815564322d0e4624ad385be0b33cf420 100644 (file)
@@ -512,7 +512,7 @@ void ieee80211_wake_queues(struct ieee80211_hw *hw)
 EXPORT_SYMBOL(ieee80211_wake_queues);
 
 void ieee80211_iterate_active_interfaces(
-       struct ieee80211_hw *hw,
+       struct ieee80211_hw *hw, u32 iter_flags,
        void (*iterator)(void *data, u8 *mac,
                         struct ieee80211_vif *vif),
        void *data)
@@ -530,6 +530,9 @@ void ieee80211_iterate_active_interfaces(
                default:
                        break;
                }
+               if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
+                   !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+                       continue;
                if (ieee80211_sdata_running(sdata))
                        iterator(data, sdata->vif.addr,
                                 &sdata->vif);
@@ -537,7 +540,9 @@ void ieee80211_iterate_active_interfaces(
 
        sdata = rcu_dereference_protected(local->monitor_sdata,
                                          lockdep_is_held(&local->iflist_mtx));
-       if (sdata)
+       if (sdata &&
+           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
+            sdata->flags & IEEE80211_SDATA_IN_DRIVER))
                iterator(data, sdata->vif.addr, &sdata->vif);
 
        mutex_unlock(&local->iflist_mtx);
@@ -545,7 +550,7 @@ void ieee80211_iterate_active_interfaces(
 EXPORT_SYMBOL_GPL(ieee80211_iterate_active_interfaces);
 
 void ieee80211_iterate_active_interfaces_atomic(
-       struct ieee80211_hw *hw,
+       struct ieee80211_hw *hw, u32 iter_flags,
        void (*iterator)(void *data, u8 *mac,
                         struct ieee80211_vif *vif),
        void *data)
@@ -563,13 +568,18 @@ void ieee80211_iterate_active_interfaces_atomic(
                default:
                        break;
                }
+               if (!(iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL) &&
+                   !(sdata->flags & IEEE80211_SDATA_IN_DRIVER))
+                       continue;
                if (ieee80211_sdata_running(sdata))
                        iterator(data, sdata->vif.addr,
                                 &sdata->vif);
        }
 
        sdata = rcu_dereference(local->monitor_sdata);
-       if (sdata)
+       if (sdata &&
+           (iter_flags & IEEE80211_IFACE_ITER_RESUME_ALL ||
+            sdata->flags & IEEE80211_SDATA_IN_DRIVER))
                iterator(data, sdata->vif.addr, &sdata->vif);
 
        rcu_read_unlock();
@@ -888,7 +898,7 @@ void ieee80211_set_wmm_default(struct ieee80211_sub_if_data *sdata,
        rcu_read_lock();
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
        use_11b = (chanctx_conf &&
-                  chanctx_conf->channel->band == IEEE80211_BAND_2GHZ) &&
+                  chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ) &&
                 !(sdata->flags & IEEE80211_SDATA_OPERATING_GMODE);
        rcu_read_unlock();
 
@@ -981,7 +991,7 @@ void ieee80211_sta_def_wmm_params(struct ieee80211_sub_if_data *sdata,
        chanctx_conf = rcu_dereference(sdata->vif.chanctx_conf);
 
        if (chanctx_conf &&
-           chanctx_conf->channel->band == IEEE80211_BAND_2GHZ &&
+           chanctx_conf->def.chan->band == IEEE80211_BAND_2GHZ &&
            have_higher_than_11mbit)
                sdata->flags |= IEEE80211_SDATA_OPERATING_GMODE;
        else
@@ -1407,10 +1417,44 @@ int ieee80211_reconfig(struct ieee80211_local *local)
        }
 
        /* add channel contexts */
-       mutex_lock(&local->chanctx_mtx);
-       list_for_each_entry(ctx, &local->chanctx_list, list)
-               WARN_ON(drv_add_chanctx(local, ctx));
-       mutex_unlock(&local->chanctx_mtx);
+       if (local->use_chanctx) {
+               mutex_lock(&local->chanctx_mtx);
+               list_for_each_entry(ctx, &local->chanctx_list, list)
+                       WARN_ON(drv_add_chanctx(local, ctx));
+               mutex_unlock(&local->chanctx_mtx);
+       }
+
+       list_for_each_entry(sdata, &local->interfaces, list) {
+               struct ieee80211_chanctx_conf *ctx_conf;
+
+               if (!ieee80211_sdata_running(sdata))
+                       continue;
+
+               mutex_lock(&local->chanctx_mtx);
+               ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                               lockdep_is_held(&local->chanctx_mtx));
+               if (ctx_conf) {
+                       ctx = container_of(ctx_conf, struct ieee80211_chanctx,
+                                          conf);
+                       drv_assign_vif_chanctx(local, sdata, ctx);
+               }
+               mutex_unlock(&local->chanctx_mtx);
+       }
+
+       sdata = rtnl_dereference(local->monitor_sdata);
+       if (sdata && local->use_chanctx && ieee80211_sdata_running(sdata)) {
+               struct ieee80211_chanctx_conf *ctx_conf;
+
+               mutex_lock(&local->chanctx_mtx);
+               ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
+                               lockdep_is_held(&local->chanctx_mtx));
+               if (ctx_conf) {
+                       ctx = container_of(ctx_conf, struct ieee80211_chanctx,
+                                          conf);
+                       drv_assign_vif_chanctx(local, sdata, ctx);
+               }
+               mutex_unlock(&local->chanctx_mtx);
+       }
 
        /* add STAs back */
        mutex_lock(&local->sta_mtx);
@@ -1452,22 +1496,11 @@ int ieee80211_reconfig(struct ieee80211_local *local)
 
        /* Finally also reconfigure all the BSS information */
        list_for_each_entry(sdata, &local->interfaces, list) {
-               struct ieee80211_chanctx_conf *ctx_conf;
                u32 changed;
 
                if (!ieee80211_sdata_running(sdata))
                        continue;
 
-               mutex_lock(&local->chanctx_mtx);
-               ctx_conf = rcu_dereference_protected(sdata->vif.chanctx_conf,
-                               lockdep_is_held(&local->chanctx_mtx));
-               if (ctx_conf) {
-                       ctx = container_of(ctx_conf, struct ieee80211_chanctx,
-                                          conf);
-                       drv_assign_vif_chanctx(local, sdata, ctx);
-               }
-               mutex_unlock(&local->chanctx_mtx);
-
                /* common change flags for all interface types */
                changed = BSS_CHANGED_ERP_CTS_PROT |
                          BSS_CHANGED_ERP_PREAMBLE |
@@ -1478,7 +1511,8 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                          BSS_CHANGED_BSSID |
                          BSS_CHANGED_CQM |
                          BSS_CHANGED_QOS |
-                         BSS_CHANGED_IDLE;
+                         BSS_CHANGED_IDLE |
+                         BSS_CHANGED_TXPOWER;
 
                switch (sdata->vif.type) {
                case NL80211_IFTYPE_STATION:
@@ -1495,9 +1529,13 @@ int ieee80211_reconfig(struct ieee80211_local *local)
                case NL80211_IFTYPE_AP:
                        changed |= BSS_CHANGED_SSID;
 
-                       if (sdata->vif.type == NL80211_IFTYPE_AP)
+                       if (sdata->vif.type == NL80211_IFTYPE_AP) {
                                changed |= BSS_CHANGED_AP_PROBE_RESP;
 
+                               if (rcu_access_pointer(sdata->u.ap.beacon))
+                                       drv_start_ap(local, sdata);
+                       }
+
                        /* fall through */
                case NL80211_IFTYPE_MESH_POINT:
                        changed |= BSS_CHANGED_BEACON |
@@ -1596,8 +1634,10 @@ int ieee80211_reconfig(struct ieee80211_local *local)
         * If this is for hw restart things are still running.
         * We may want to change that later, however.
         */
-       if (!local->suspended)
+       if (!local->suspended) {
+               drv_restart_complete(local);
                return 0;
+       }
 
 #ifdef CONFIG_PM
        /* first set suspended false, then resuming */
@@ -1833,8 +1873,7 @@ u8 *ieee80211_ie_build_vht_cap(u8 *pos, struct ieee80211_sta_vht_cap *vht_cap,
 }
 
 u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
-                              struct ieee80211_channel *channel,
-                              enum nl80211_channel_type channel_type,
+                              const struct cfg80211_chan_def *chandef,
                               u16 prot_mode)
 {
        struct ieee80211_ht_operation *ht_oper;
@@ -1842,23 +1881,25 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
        *pos++ = WLAN_EID_HT_OPERATION;
        *pos++ = sizeof(struct ieee80211_ht_operation);
        ht_oper = (struct ieee80211_ht_operation *)pos;
-       ht_oper->primary_chan =
-                       ieee80211_frequency_to_channel(channel->center_freq);
-       switch (channel_type) {
-       case NL80211_CHAN_HT40MINUS:
-               ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
-               break;
-       case NL80211_CHAN_HT40PLUS:
-               ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+       ht_oper->primary_chan = ieee80211_frequency_to_channel(
+                                       chandef->chan->center_freq);
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_160:
+       case NL80211_CHAN_WIDTH_80P80:
+       case NL80211_CHAN_WIDTH_80:
+       case NL80211_CHAN_WIDTH_40:
+               if (chandef->center_freq1 > chandef->chan->center_freq)
+                       ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_ABOVE;
+               else
+                       ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_BELOW;
                break;
-       case NL80211_CHAN_HT20:
        default:
                ht_oper->ht_param = IEEE80211_HT_PARAM_CHA_SEC_NONE;
                break;
        }
        if (ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40 &&
-           channel_type != NL80211_CHAN_NO_HT &&
-           channel_type != NL80211_CHAN_HT20)
+           chandef->width != NL80211_CHAN_WIDTH_20_NOHT &&
+           chandef->width != NL80211_CHAN_WIDTH_20)
                ht_oper->ht_param |= IEEE80211_HT_PARAM_CHAN_WIDTH_ANY;
 
        ht_oper->operation_mode = cpu_to_le16(prot_mode);
@@ -1872,13 +1913,17 @@ u8 *ieee80211_ie_build_ht_oper(u8 *pos, struct ieee80211_sta_ht_cap *ht_cap,
        return pos + sizeof(struct ieee80211_ht_operation);
 }
 
-enum nl80211_channel_type
-ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper)
+void ieee80211_ht_oper_to_chandef(struct ieee80211_channel *control_chan,
+                                 struct ieee80211_ht_operation *ht_oper,
+                                 struct cfg80211_chan_def *chandef)
 {
        enum nl80211_channel_type channel_type;
 
-       if (!ht_oper)
-               return NL80211_CHAN_NO_HT;
+       if (!ht_oper) {
+               cfg80211_chandef_create(chandef, control_chan,
+                                       NL80211_CHAN_NO_HT);
+               return;
+       }
 
        switch (ht_oper->ht_param & IEEE80211_HT_PARAM_CHA_SEC_OFFSET) {
        case IEEE80211_HT_PARAM_CHA_SEC_NONE:
@@ -1894,7 +1939,7 @@ ieee80211_ht_oper_to_channel_type(struct ieee80211_ht_operation *ht_oper)
                channel_type = NL80211_CHAN_NO_HT;
        }
 
-       return channel_type;
+       cfg80211_chandef_create(chandef, control_chan, channel_type);
 }
 
 int ieee80211_add_srates_ie(struct ieee80211_sub_if_data *sdata,
@@ -1992,3 +2037,68 @@ u8 ieee80211_mcs_to_chains(const struct ieee80211_mcs_info *mcs)
                return 2;
        return 1;
 }
+
+/**
+ * ieee80211_calculate_rx_timestamp - calculate timestamp in frame
+ * @local: mac80211 hw info struct
+ * @status: RX status
+ * @mpdu_len: total MPDU length (including FCS)
+ * @mpdu_offset: offset into MPDU to calculate timestamp at
+ *
+ * This function calculates the RX timestamp at the given MPDU offset, taking
+ * into account what the RX timestamp was. An offset of 0 will just normalize
+ * the timestamp to TSF at beginning of MPDU reception.
+ */
+u64 ieee80211_calculate_rx_timestamp(struct ieee80211_local *local,
+                                    struct ieee80211_rx_status *status,
+                                    unsigned int mpdu_len,
+                                    unsigned int mpdu_offset)
+{
+       u64 ts = status->mactime;
+       struct rate_info ri;
+       u16 rate;
+
+       if (WARN_ON(!ieee80211_have_rx_timestamp(status)))
+               return 0;
+
+       memset(&ri, 0, sizeof(ri));
+
+       /* Fill cfg80211 rate info */
+       if (status->flag & RX_FLAG_HT) {
+               ri.mcs = status->rate_idx;
+               ri.flags |= RATE_INFO_FLAGS_MCS;
+               if (status->flag & RX_FLAG_40MHZ)
+                       ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+               if (status->flag & RX_FLAG_SHORT_GI)
+                       ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
+       } else if (status->flag & RX_FLAG_VHT) {
+               ri.flags |= RATE_INFO_FLAGS_VHT_MCS;
+               ri.mcs = status->rate_idx;
+               ri.nss = status->vht_nss;
+               if (status->flag & RX_FLAG_40MHZ)
+                       ri.flags |= RATE_INFO_FLAGS_40_MHZ_WIDTH;
+               if (status->flag & RX_FLAG_80MHZ)
+                       ri.flags |= RATE_INFO_FLAGS_80_MHZ_WIDTH;
+               if (status->flag & RX_FLAG_80P80MHZ)
+                       ri.flags |= RATE_INFO_FLAGS_80P80_MHZ_WIDTH;
+               if (status->flag & RX_FLAG_160MHZ)
+                       ri.flags |= RATE_INFO_FLAGS_160_MHZ_WIDTH;
+               if (status->flag & RX_FLAG_SHORT_GI)
+                       ri.flags |= RATE_INFO_FLAGS_SHORT_GI;
+       } else {
+               struct ieee80211_supported_band *sband;
+
+               sband = local->hw.wiphy->bands[status->band];
+               ri.legacy = sband->bitrates[status->rate_idx].bitrate;
+       }
+
+       rate = cfg80211_calculate_bitrate(&ri);
+
+       /* rewind from end of MPDU */
+       if (status->flag & RX_FLAG_MACTIME_END)
+               ts -= mpdu_len * 8 * 10 / rate;
+
+       ts += mpdu_offset * 8 * 10 / rate;
+
+       return ts;
+}
index cea06e9f26f480b48a58747fc98f5665a3ead21c..906f00cd6d2f65053281c617254f9f50681ec403 100644 (file)
@@ -160,31 +160,37 @@ u16 ieee80211_select_queue(struct ieee80211_sub_if_data *sdata,
        return ieee80211_downgrade_queue(sdata, skb);
 }
 
+/**
+ * ieee80211_set_qos_hdr - Fill in the QoS header if there is one.
+ *
+ * @sdata: local subif
+ * @skb: packet to be updated
+ */
 void ieee80211_set_qos_hdr(struct ieee80211_sub_if_data *sdata,
                           struct sk_buff *skb)
 {
        struct ieee80211_hdr *hdr = (void *)skb->data;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       u8 *p;
+       u8 ack_policy, tid;
 
-       /* Fill in the QoS header if there is one. */
-       if (ieee80211_is_data_qos(hdr->frame_control)) {
-               u8 *p = ieee80211_get_qos_ctl(hdr);
-               u8 ack_policy, tid;
-
-               tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
+       if (!ieee80211_is_data_qos(hdr->frame_control))
+               return;
 
-               /* preserve EOSP bit */
-               ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
+       p = ieee80211_get_qos_ctl(hdr);
+       tid = skb->priority & IEEE80211_QOS_CTL_TAG1D_MASK;
 
-               if (is_multicast_ether_addr(hdr->addr1) ||
-                   sdata->noack_map & BIT(tid)) {
-                       ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
-                       info->flags |= IEEE80211_TX_CTL_NO_ACK;
-               }
+       /* preserve EOSP bit */
+       ack_policy = *p & IEEE80211_QOS_CTL_EOSP;
 
-               /* qos header is 2 bytes */
-               *p++ = ack_policy | tid;
-               *p = ieee80211_vif_is_mesh(&sdata->vif) ?
-                       (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0;
+       if (is_multicast_ether_addr(hdr->addr1) ||
+           sdata->noack_map & BIT(tid)) {
+               ack_policy |= IEEE80211_QOS_CTL_ACK_POLICY_NOACK;
+               info->flags |= IEEE80211_TX_CTL_NO_ACK;
        }
+
+       /* qos header is 2 bytes */
+       *p++ = ack_policy | tid;
+       *p = ieee80211_vif_is_mesh(&sdata->vif) ?
+               (IEEE80211_QOS_CTL_MESH_CONTROL_PRESENT >> 8) : 0;
 }
index 07659cfd6d7b9fab1cc2c241c39ae2ef92c0cc2b..7d99410e6c1a542d91795a40f5e9d8bf9e719c5f 100644 (file)
@@ -344,7 +344,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate,
                return -EADDRINUSE;
 
        if (pipe != NFC_HCI_INVALID_PIPE)
-               goto pipe_is_open;
+               goto open_pipe;
 
        switch (dest_gate) {
        case NFC_HCI_LINK_MGMT_GATE:
@@ -361,6 +361,7 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate,
                break;
        }
 
+open_pipe:
        r = nfc_hci_open_pipe(hdev, pipe);
        if (r < 0) {
                if (pipe_created)
@@ -371,7 +372,6 @@ int nfc_hci_connect_gate(struct nfc_hci_dev *hdev, u8 dest_host, u8 dest_gate,
                return r;
        }
 
-pipe_is_open:
        hdev->gate2pipe[dest_gate] = pipe;
 
        return 0;
index bc571b0efb9228b97b6c4e19a6809adb6be2c0f3..7bea574d59344f754ad74a1a390a8d742843549b 100644 (file)
 /* Largest headroom needed for outgoing HCI commands */
 #define HCI_CMDS_HEADROOM 1
 
-static int nfc_hci_result_to_errno(u8 result)
+int nfc_hci_result_to_errno(u8 result)
 {
        switch (result) {
        case NFC_HCI_ANY_OK:
                return 0;
+       case NFC_HCI_ANY_E_REG_PAR_UNKNOWN:
+               return -EOPNOTSUPP;
        case NFC_HCI_ANY_E_TIMEOUT:
                return -ETIME;
        default:
                return -1;
        }
 }
+EXPORT_SYMBOL(nfc_hci_result_to_errno);
 
 static void nfc_hci_msg_tx_work(struct work_struct *work)
 {
@@ -167,7 +170,7 @@ void nfc_hci_cmd_received(struct nfc_hci_dev *hdev, u8 pipe, u8 cmd,
        kfree_skb(skb);
 }
 
-static u32 nfc_hci_sak_to_protocol(u8 sak)
+u32 nfc_hci_sak_to_protocol(u8 sak)
 {
        switch (NFC_HCI_TYPE_A_SEL_PROT(sak)) {
        case NFC_HCI_TYPE_A_SEL_PROT_MIFARE:
@@ -182,6 +185,7 @@ static u32 nfc_hci_sak_to_protocol(u8 sak)
                return 0xffffffff;
        }
 }
+EXPORT_SYMBOL(nfc_hci_sak_to_protocol);
 
 int nfc_hci_target_discovered(struct nfc_hci_dev *hdev, u8 gate)
 {
@@ -284,6 +288,12 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
                            struct sk_buff *skb)
 {
        int r = 0;
+       u8 gate = nfc_hci_pipe2gate(hdev, pipe);
+
+       if (gate == 0xff) {
+               pr_err("Discarded event %x to unopened pipe %x\n", event, pipe);
+               goto exit;
+       }
 
        switch (event) {
        case NFC_HCI_EVT_TARGET_DISCOVERED:
@@ -307,14 +317,11 @@ void nfc_hci_event_received(struct nfc_hci_dev *hdev, u8 pipe, u8 event,
                        goto exit;
                }
 
-               r = nfc_hci_target_discovered(hdev,
-                                             nfc_hci_pipe2gate(hdev, pipe));
+               r = nfc_hci_target_discovered(hdev, gate);
                break;
        default:
                if (hdev->ops->event_received) {
-                       hdev->ops->event_received(hdev,
-                                               nfc_hci_pipe2gate(hdev, pipe),
-                                               event, skb);
+                       hdev->ops->event_received(hdev, gate, event, skb);
                        return;
                }
 
@@ -419,6 +426,10 @@ static int hci_dev_version(struct nfc_hci_dev *hdev)
 
        r = nfc_hci_get_param(hdev, NFC_HCI_ID_MGMT_GATE,
                              NFC_HCI_ID_MGMT_VERSION_SW, &skb);
+       if (r == -EOPNOTSUPP) {
+               pr_info("Software/Hardware info not available\n");
+               return 0;
+       }
        if (r < 0)
                return r;
 
index ed2d17312d61d79bc224183e1e58e4fc11d208be..df24be48d4dad2ee998bb483bdd4b1d109b24333 100644 (file)
@@ -528,6 +528,23 @@ int nfc_llcp_send_i_frame(struct nfc_llcp_sock *sock,
        if (local == NULL)
                return -ENODEV;
 
+       /* Remote is ready but has not acknowledged our frames */
+       if((sock->remote_ready &&
+           skb_queue_len(&sock->tx_pending_queue) >= sock->rw &&
+           skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) {
+               pr_err("Pending queue is full %d frames\n",
+                      skb_queue_len(&sock->tx_pending_queue));
+               return -ENOBUFS;
+       }
+
+       /* Remote is not ready and we've been queueing enough frames */
+       if ((!sock->remote_ready &&
+            skb_queue_len(&sock->tx_queue) >= 2 * sock->rw)) {
+               pr_err("Tx queue is full %d frames\n",
+                      skb_queue_len(&sock->tx_queue));
+               return -ENOBUFS;
+       }
+
        msg_data = kzalloc(len, GFP_KERNEL);
        if (msg_data == NULL)
                return -ENOMEM;
@@ -579,7 +596,7 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
        struct sk_buff *pdu;
        struct nfc_llcp_local *local;
        size_t frag_len = 0, remaining_len;
-       u8 *msg_ptr;
+       u8 *msg_ptr, *msg_data;
        int err;
 
        pr_debug("Send UI frame len %zd\n", len);
@@ -588,8 +605,17 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
        if (local == NULL)
                return -ENODEV;
 
+       msg_data = kzalloc(len, GFP_KERNEL);
+       if (msg_data == NULL)
+               return -ENOMEM;
+
+       if (memcpy_fromiovec(msg_data, msg->msg_iov, len)) {
+               kfree(msg_data);
+               return -EFAULT;
+       }
+
        remaining_len = len;
-       msg_ptr = (u8 *) msg->msg_iov;
+       msg_ptr = msg_data;
 
        while (remaining_len > 0) {
 
@@ -616,6 +642,8 @@ int nfc_llcp_send_ui_frame(struct nfc_llcp_sock *sock, u8 ssap, u8 dsap,
                msg_ptr += frag_len;
        }
 
+       kfree(msg_data);
+
        return len;
 }
 
index 2e9ddf34c099a3bc6767687d562e2112f16e7972..2df87056c6dfa7b52dc95eb2601571a655d02386 100644 (file)
@@ -656,6 +656,8 @@ static void nfc_llcp_tx_work(struct work_struct *work)
                if (llcp_sock == NULL && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
                        nfc_llcp_send_symm(local->dev);
                } else {
+                       struct sk_buff *copy_skb = NULL;
+                       u8 ptype = nfc_llcp_ptype(skb);
                        int ret;
 
                        pr_debug("Sending pending skb\n");
@@ -663,22 +665,29 @@ static void nfc_llcp_tx_work(struct work_struct *work)
                                       DUMP_PREFIX_OFFSET, 16, 1,
                                       skb->data, skb->len, true);
 
+                       if (ptype == LLCP_PDU_I)
+                               copy_skb = skb_copy(skb, GFP_ATOMIC);
+
                        nfc_llcp_send_to_raw_sock(local, skb,
                                                  NFC_LLCP_DIRECTION_TX);
 
                        ret = nfc_data_exchange(local->dev, local->target_idx,
                                                skb, nfc_llcp_recv, local);
 
-                       if (!ret && nfc_llcp_ptype(skb) == LLCP_PDU_I) {
-                               skb = skb_get(skb);
-                               skb_queue_tail(&llcp_sock->tx_pending_queue,
-                                              skb);
+                       if (ret) {
+                               kfree_skb(copy_skb);
+                               goto out;
                        }
+
+                       if (ptype == LLCP_PDU_I && copy_skb)
+                               skb_queue_tail(&llcp_sock->tx_pending_queue,
+                                              copy_skb);
                }
        } else {
                nfc_llcp_send_symm(local->dev);
        }
 
+out:
        mod_timer(&local->link_timer,
                  jiffies + msecs_to_jiffies(2 * local->remote_lto));
 }
index fe4adb12b3ef494e407b9531a62624869158260a..16d08b39921071479456e2033c5e371d381175b7 100644 (file)
@@ -140,14 +140,13 @@ config CFG80211_WEXT
          extensions with cfg80211-based drivers.
 
 config LIB80211
-       tristate "Common routines for IEEE802.11 drivers"
+       tristate
        default n
        help
          This options enables a library of common routines used
          by IEEE802.11 wireless LAN drivers.
 
-         Drivers should select this themselves if needed.  Say Y if
-         you want this built into your kernel.
+         Drivers should select this themselves if needed.
 
 config LIB80211_CRYPT_WEP
        tristate
index e143505f05bc1e856720458e71c3ed41de907902..324e8d851dc4ca67fd0ded84a927e782c3647c8c 100644 (file)
@@ -28,6 +28,7 @@ static int __cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
        if (!err) {
                wdev->beacon_interval = 0;
                wdev->channel = NULL;
+               wdev->ssid_len = 0;
        }
 
        return err;
index 48febd2160ba488a7b8fccea612de1ae76b2c3fa..bf2dfd54ff3ba6c0b2f673d37f790dca0a4aedce 100644 (file)
 #include "core.h"
 #include "rdev-ops.h"
 
-struct ieee80211_channel *
-rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
-                 int freq, enum nl80211_channel_type channel_type)
+void cfg80211_chandef_create(struct cfg80211_chan_def *chandef,
+                            struct ieee80211_channel *chan,
+                            enum nl80211_channel_type chan_type)
 {
-       struct ieee80211_channel *chan;
-       struct ieee80211_sta_ht_cap *ht_cap;
+       if (WARN_ON(!chan))
+               return;
 
-       chan = ieee80211_get_channel(&rdev->wiphy, freq);
+       chandef->chan = chan;
+       chandef->center_freq2 = 0;
 
-       /* Primary channel not allowed */
-       if (!chan || chan->flags & IEEE80211_CHAN_DISABLED)
-               return NULL;
+       switch (chan_type) {
+       case NL80211_CHAN_NO_HT:
+               chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+               chandef->center_freq1 = chan->center_freq;
+               break;
+       case NL80211_CHAN_HT20:
+               chandef->width = NL80211_CHAN_WIDTH_20;
+               chandef->center_freq1 = chan->center_freq;
+               break;
+       case NL80211_CHAN_HT40PLUS:
+               chandef->width = NL80211_CHAN_WIDTH_40;
+               chandef->center_freq1 = chan->center_freq + 10;
+               break;
+       case NL80211_CHAN_HT40MINUS:
+               chandef->width = NL80211_CHAN_WIDTH_40;
+               chandef->center_freq1 = chan->center_freq - 10;
+               break;
+       default:
+               WARN_ON(1);
+       }
+}
+EXPORT_SYMBOL(cfg80211_chandef_create);
 
-       if (channel_type == NL80211_CHAN_HT40MINUS &&
-           chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
-               return NULL;
-       else if (channel_type == NL80211_CHAN_HT40PLUS &&
-                chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
-               return NULL;
+bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef)
+{
+       u32 control_freq;
 
-       ht_cap = &rdev->wiphy.bands[chan->band]->ht_cap;
+       if (!chandef->chan)
+               return false;
 
-       if (channel_type != NL80211_CHAN_NO_HT) {
-               if (!ht_cap->ht_supported)
-                       return NULL;
+       control_freq = chandef->chan->center_freq;
 
-               if (channel_type != NL80211_CHAN_HT20 &&
-                   (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
-                   ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT))
-                       return NULL;
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_20:
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               if (chandef->center_freq1 != control_freq)
+                       return false;
+               if (chandef->center_freq2)
+                       return false;
+               break;
+       case NL80211_CHAN_WIDTH_40:
+               if (chandef->center_freq1 != control_freq + 10 &&
+                   chandef->center_freq1 != control_freq - 10)
+                       return false;
+               if (chandef->center_freq2)
+                       return false;
+               break;
+       case NL80211_CHAN_WIDTH_80P80:
+               if (chandef->center_freq1 != control_freq + 30 &&
+                   chandef->center_freq1 != control_freq + 10 &&
+                   chandef->center_freq1 != control_freq - 10 &&
+                   chandef->center_freq1 != control_freq - 30)
+                       return false;
+               if (!chandef->center_freq2)
+                       return false;
+               break;
+       case NL80211_CHAN_WIDTH_80:
+               if (chandef->center_freq1 != control_freq + 30 &&
+                   chandef->center_freq1 != control_freq + 10 &&
+                   chandef->center_freq1 != control_freq - 10 &&
+                   chandef->center_freq1 != control_freq - 30)
+                       return false;
+               if (chandef->center_freq2)
+                       return false;
+               break;
+       case NL80211_CHAN_WIDTH_160:
+               if (chandef->center_freq1 != control_freq + 70 &&
+                   chandef->center_freq1 != control_freq + 50 &&
+                   chandef->center_freq1 != control_freq + 30 &&
+                   chandef->center_freq1 != control_freq + 10 &&
+                   chandef->center_freq1 != control_freq - 10 &&
+                   chandef->center_freq1 != control_freq - 30 &&
+                   chandef->center_freq1 != control_freq - 50 &&
+                   chandef->center_freq1 != control_freq - 70)
+                       return false;
+               if (chandef->center_freq2)
+                       return false;
+               break;
+       default:
+               return false;
        }
 
-       return chan;
+       return true;
 }
 
-bool cfg80211_can_beacon_sec_chan(struct wiphy *wiphy,
-                                 struct ieee80211_channel *chan,
-                                 enum nl80211_channel_type channel_type)
+static void chandef_primary_freqs(const struct cfg80211_chan_def *c,
+                                 int *pri40, int *pri80)
 {
-       struct ieee80211_channel *sec_chan;
-       int diff;
-
-       trace_cfg80211_can_beacon_sec_chan(wiphy, chan, channel_type);
+       int tmp;
 
-       switch (channel_type) {
-       case NL80211_CHAN_HT40PLUS:
-               diff = 20;
+       switch (c->width) {
+       case NL80211_CHAN_WIDTH_40:
+               *pri40 = c->center_freq1;
+               *pri80 = 0;
                break;
-       case NL80211_CHAN_HT40MINUS:
-               diff = -20;
+       case NL80211_CHAN_WIDTH_80:
+       case NL80211_CHAN_WIDTH_80P80:
+               *pri80 = c->center_freq1;
+               /* n_P20 */
+               tmp = (30 + c->chan->center_freq - c->center_freq1)/20;
+               /* n_P40 */
+               tmp /= 2;
+               /* freq_P40 */
+               *pri40 = c->center_freq1 - 20 + 40 * tmp;
+               break;
+       case NL80211_CHAN_WIDTH_160:
+               /* n_P20 */
+               tmp = (70 + c->chan->center_freq - c->center_freq1)/20;
+               /* n_P40 */
+               tmp /= 2;
+               /* freq_P40 */
+               *pri40 = c->center_freq1 - 60 + 40 * tmp;
+               /* n_P80 */
+               tmp /= 2;
+               *pri80 = c->center_freq1 - 40 + 80 * tmp;
                break;
        default:
-               trace_cfg80211_return_bool(true);
-               return true;
+               WARN_ON_ONCE(1);
        }
+}
+
+const struct cfg80211_chan_def *
+cfg80211_chandef_compatible(const struct cfg80211_chan_def *c1,
+                           const struct cfg80211_chan_def *c2)
+{
+       u32 c1_pri40, c1_pri80, c2_pri40, c2_pri80;
 
-       sec_chan = ieee80211_get_channel(wiphy, chan->center_freq + diff);
-       if (!sec_chan) {
+       /* If they are identical, return */
+       if (cfg80211_chandef_identical(c1, c2))
+               return c1;
+
+       /* otherwise, must have same control channel */
+       if (c1->chan != c2->chan)
+               return NULL;
+
+       /*
+        * If they have the same width, but aren't identical,
+        * then they can't be compatible.
+        */
+       if (c1->width == c2->width)
+               return NULL;
+
+       if (c1->width == NL80211_CHAN_WIDTH_20_NOHT ||
+           c1->width == NL80211_CHAN_WIDTH_20)
+               return c2;
+
+       if (c2->width == NL80211_CHAN_WIDTH_20_NOHT ||
+           c2->width == NL80211_CHAN_WIDTH_20)
+               return c1;
+
+       chandef_primary_freqs(c1, &c1_pri40, &c1_pri80);
+       chandef_primary_freqs(c2, &c2_pri40, &c2_pri80);
+
+       if (c1_pri40 != c2_pri40)
+               return NULL;
+
+       WARN_ON(!c1_pri80 && !c2_pri80);
+       if (c1_pri80 && c2_pri80 && c1_pri80 != c2_pri80)
+               return NULL;
+
+       if (c1->width > c2->width)
+               return c1;
+       return c2;
+}
+EXPORT_SYMBOL(cfg80211_chandef_compatible);
+
+bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
+                                u32 center_freq, u32 bandwidth,
+                                u32 prohibited_flags)
+{
+       struct ieee80211_channel *c;
+       u32 freq;
+
+       for (freq = center_freq - bandwidth/2 + 10;
+            freq <= center_freq + bandwidth/2 - 10;
+            freq += 20) {
+               c = ieee80211_get_channel(wiphy, freq);
+               if (!c || c->flags & prohibited_flags)
+                       return false;
+       }
+
+       return true;
+}
+
+static bool cfg80211_check_beacon_chans(struct wiphy *wiphy,
+                                       u32 center_freq, u32 bw)
+{
+       return cfg80211_secondary_chans_ok(wiphy, center_freq, bw,
+                                          IEEE80211_CHAN_DISABLED |
+                                          IEEE80211_CHAN_PASSIVE_SCAN |
+                                          IEEE80211_CHAN_NO_IBSS |
+                                          IEEE80211_CHAN_RADAR);
+}
+
+bool cfg80211_reg_can_beacon(struct wiphy *wiphy,
+                            struct cfg80211_chan_def *chandef)
+{
+       u32 width;
+       bool res;
+
+       trace_cfg80211_reg_can_beacon(wiphy, chandef);
+
+       if (WARN_ON(!cfg80211_chan_def_valid(chandef))) {
                trace_cfg80211_return_bool(false);
                return false;
        }
 
-       /* we'll need a DFS capability later */
-       if (sec_chan->flags & (IEEE80211_CHAN_DISABLED |
-                              IEEE80211_CHAN_PASSIVE_SCAN |
-                              IEEE80211_CHAN_NO_IBSS |
-                              IEEE80211_CHAN_RADAR)) {
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+       case NL80211_CHAN_WIDTH_20:
+               width = 20;
+               break;
+       case NL80211_CHAN_WIDTH_40:
+               width = 40;
+               break;
+       case NL80211_CHAN_WIDTH_80:
+       case NL80211_CHAN_WIDTH_80P80:
+               width = 80;
+               break;
+       case NL80211_CHAN_WIDTH_160:
+               width = 160;
+               break;
+       default:
+               WARN_ON_ONCE(1);
                trace_cfg80211_return_bool(false);
                return false;
        }
-       trace_cfg80211_return_bool(true);
-       return true;
+
+       res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq1, width);
+
+       if (res && chandef->center_freq2)
+               res = cfg80211_check_beacon_chans(wiphy, chandef->center_freq2,
+                                                 width);
+
+       trace_cfg80211_return_bool(res);
+       return res;
 }
-EXPORT_SYMBOL(cfg80211_can_beacon_sec_chan);
+EXPORT_SYMBOL(cfg80211_reg_can_beacon);
 
 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
-                                int freq, enum nl80211_channel_type chantype)
+                                struct cfg80211_chan_def *chandef)
 {
-       struct ieee80211_channel *chan;
-
        if (!rdev->ops->set_monitor_channel)
                return -EOPNOTSUPP;
        if (!cfg80211_has_monitors_only(rdev))
                return -EBUSY;
 
-       chan = rdev_freq_to_chan(rdev, freq, chantype);
-       if (!chan)
-               return -EINVAL;
-
-       return rdev_set_monitor_channel(rdev, chan, chantype);
+       return rdev_set_monitor_channel(rdev, chandef);
 }
 
 void
index 26711f46a3beeac6eddd0c50c13e49a70dd22cef..14d990400354200056e99d14132d6e7ab2504ccb 100644 (file)
@@ -326,6 +326,8 @@ struct wiphy *wiphy_new(const struct cfg80211_ops *ops, int sizeof_priv)
        mutex_init(&rdev->devlist_mtx);
        mutex_init(&rdev->sched_scan_mtx);
        INIT_LIST_HEAD(&rdev->wdev_list);
+       INIT_LIST_HEAD(&rdev->beacon_registrations);
+       spin_lock_init(&rdev->beacon_registrations_lock);
        spin_lock_init(&rdev->bss_lock);
        INIT_LIST_HEAD(&rdev->bss_list);
        INIT_WORK(&rdev->scan_done_wk, __cfg80211_scan_done);
@@ -698,10 +700,15 @@ EXPORT_SYMBOL(wiphy_unregister);
 void cfg80211_dev_free(struct cfg80211_registered_device *rdev)
 {
        struct cfg80211_internal_bss *scan, *tmp;
+       struct cfg80211_beacon_registration *reg, *treg;
        rfkill_destroy(rdev->rfkill);
        mutex_destroy(&rdev->mtx);
        mutex_destroy(&rdev->devlist_mtx);
        mutex_destroy(&rdev->sched_scan_mtx);
+       list_for_each_entry_safe(reg, treg, &rdev->beacon_registrations, list) {
+               list_del(&reg->list);
+               kfree(reg);
+       }
        list_for_each_entry_safe(scan, tmp, &rdev->bss_list, list)
                cfg80211_put_bss(&scan->pub);
        kfree(rdev);
index b8eb743fe7daf737baf3a0bd79884f0551da17f1..a0c8decf6a4758a9f50796d06396696a3072f1c8 100644 (file)
@@ -55,7 +55,8 @@ struct cfg80211_registered_device {
        int opencount; /* also protected by devlist_mtx */
        wait_queue_head_t dev_wait;
 
-       u32 ap_beacons_nlportid;
+       struct list_head beacon_registrations;
+       spinlock_t beacon_registrations_lock;
 
        /* protected by RTNL only */
        int num_running_ifaces;
@@ -260,6 +261,10 @@ enum cfg80211_chan_mode {
        CHAN_MODE_EXCLUSIVE,
 };
 
+struct cfg80211_beacon_registration {
+       struct list_head list;
+       u32 nlportid;
+};
 
 /* free object */
 extern void cfg80211_dev_free(struct cfg80211_registered_device *rdev);
@@ -304,9 +309,9 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                       const struct mesh_config *conf);
 int cfg80211_leave_mesh(struct cfg80211_registered_device *rdev,
                        struct net_device *dev);
-int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
-                          struct wireless_dev *wdev, int freq,
-                          enum nl80211_channel_type channel_type);
+int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
+                             struct wireless_dev *wdev,
+                             struct cfg80211_chan_def *chandef);
 
 /* AP */
 int cfg80211_stop_ap(struct cfg80211_registered_device *rdev,
@@ -373,10 +378,8 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev);
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct wireless_dev *wdev,
                          struct ieee80211_channel *chan, bool offchan,
-                         enum nl80211_channel_type channel_type,
-                         bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, bool no_cck,
-                         bool dont_wait_for_ack, u64 *cookie);
+                         unsigned int wait, const u8 *buf, size_t len,
+                         bool no_cck, bool dont_wait_for_ack, u64 *cookie);
 void cfg80211_oper_and_ht_capa(struct ieee80211_ht_cap *ht_capa,
                               const struct ieee80211_ht_cap *ht_capa_mask);
 
@@ -467,11 +470,8 @@ cfg80211_get_chan_state(struct wireless_dev *wdev,
                        struct ieee80211_channel **chan,
                        enum cfg80211_chan_mode *chanmode);
 
-struct ieee80211_channel *
-rdev_freq_to_chan(struct cfg80211_registered_device *rdev,
-                 int freq, enum nl80211_channel_type channel_type);
 int cfg80211_set_monitor_channel(struct cfg80211_registered_device *rdev,
-                                int freq, enum nl80211_channel_type chantype);
+                                struct cfg80211_chan_def *chandef);
 
 int ieee80211_get_ratemask(struct ieee80211_supported_band *sband,
                           const u8 *rates, unsigned int n_rates,
@@ -483,6 +483,12 @@ int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
 void cfg80211_update_iface_num(struct cfg80211_registered_device *rdev,
                               enum nl80211_iftype iftype, int num);
 
+bool cfg80211_chan_def_valid(const struct cfg80211_chan_def *chandef);
+
+bool cfg80211_secondary_chans_ok(struct wiphy *wiphy,
+                                u32 center_freq, u32 bandwidth,
+                                u32 prohibited_flags);
+
 #define CFG80211_MAX_NUM_DIFFERENT_CHANNELS 10
 
 #ifdef CONFIG_CFG80211_DEVELOPER_WARNINGS
index 27941d5db72bd609531d4017604ece5fdea119fd..9b9551e4a6f9780a6b9fe6096949f9f86fd315ad 100644 (file)
@@ -100,9 +100,9 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
                * 11a for maximum compatibility.
                */
                struct ieee80211_supported_band *sband =
-                       rdev->wiphy.bands[params->channel->band];
+                       rdev->wiphy.bands[params->chandef.chan->band];
                int j;
-               u32 flag = params->channel->band == IEEE80211_BAND_5GHZ ?
+               u32 flag = params->chandef.chan->band == IEEE80211_BAND_5GHZ ?
                        IEEE80211_RATE_MANDATORY_A :
                        IEEE80211_RATE_MANDATORY_B;
 
@@ -118,11 +118,11 @@ int __cfg80211_join_ibss(struct cfg80211_registered_device *rdev,
 
        wdev->ibss_fixed = params->channel_fixed;
 #ifdef CONFIG_CFG80211_WEXT
-       wdev->wext.ibss.channel = params->channel;
+       wdev->wext.ibss.chandef = params->chandef;
 #endif
        wdev->sme_state = CFG80211_SME_CONNECTING;
 
-       err = cfg80211_can_use_chan(rdev, wdev, params->channel,
+       err = cfg80211_can_use_chan(rdev, wdev, params->chandef.chan,
                                    params->channel_fixed
                                    ? CHAN_MODE_SHARED
                                    : CHAN_MODE_EXCLUSIVE);
@@ -251,7 +251,9 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
                wdev->wext.ibss.beacon_interval = 100;
 
        /* try to find an IBSS channel if none requested ... */
-       if (!wdev->wext.ibss.channel) {
+       if (!wdev->wext.ibss.chandef.chan) {
+               wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
+
                for (band = 0; band < IEEE80211_NUM_BANDS; band++) {
                        struct ieee80211_supported_band *sband;
                        struct ieee80211_channel *chan;
@@ -266,15 +268,15 @@ int cfg80211_ibss_wext_join(struct cfg80211_registered_device *rdev,
                                        continue;
                                if (chan->flags & IEEE80211_CHAN_DISABLED)
                                        continue;
-                               wdev->wext.ibss.channel = chan;
+                               wdev->wext.ibss.chandef.chan = chan;
                                break;
                        }
 
-                       if (wdev->wext.ibss.channel)
+                       if (wdev->wext.ibss.chandef.chan)
                                break;
                }
 
-               if (!wdev->wext.ibss.channel)
+               if (!wdev->wext.ibss.chandef.chan)
                        return -EINVAL;
        }
 
@@ -336,7 +338,7 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
                        return -EINVAL;
        }
 
-       if (wdev->wext.ibss.channel == chan)
+       if (wdev->wext.ibss.chandef.chan == chan)
                return 0;
 
        wdev_lock(wdev);
@@ -349,7 +351,8 @@ int cfg80211_ibss_wext_siwfreq(struct net_device *dev,
                return err;
 
        if (chan) {
-               wdev->wext.ibss.channel = chan;
+               wdev->wext.ibss.chandef.chan = chan;
+               wdev->wext.ibss.chandef.width = NL80211_CHAN_WIDTH_20_NOHT;
                wdev->wext.ibss.channel_fixed = true;
        } else {
                /* cfg80211_ibss_wext_join will pick one if needed */
@@ -379,8 +382,8 @@ int cfg80211_ibss_wext_giwfreq(struct net_device *dev,
        wdev_lock(wdev);
        if (wdev->current_bss)
                chan = wdev->current_bss->pub.channel;
-       else if (wdev->wext.ibss.channel)
-               chan = wdev->wext.ibss.channel;
+       else if (wdev->wext.ibss.chandef.chan)
+               chan = wdev->wext.ibss.chandef.chan;
        wdev_unlock(wdev);
 
        if (chan) {
index 966cfc4cd79dc0e7dd47a819022470c7eb158996..3ee5a72822839fc945dcad821a24af0defcb5854 100644 (file)
@@ -73,8 +73,6 @@ const struct mesh_config default_mesh_config = {
 
 const struct mesh_setup default_mesh_setup = {
        /* cfg80211_join_mesh() will pick a channel if needed */
-       .channel = NULL,
-       .channel_type = NL80211_CHAN_NO_HT,
        .sync_method = IEEE80211_SYNC_METHOD_NEIGHBOR_OFFSET,
        .path_sel_proto = IEEE80211_PATH_PROTOCOL_HWMP,
        .path_metric = IEEE80211_PATH_METRIC_AIRTIME,
@@ -111,13 +109,12 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
        if (!rdev->ops->join_mesh)
                return -EOPNOTSUPP;
 
-       if (!setup->channel) {
+       if (!setup->chandef.chan) {
                /* if no channel explicitly given, use preset channel */
-               setup->channel = wdev->preset_chan;
-               setup->channel_type = wdev->preset_chantype;
+               setup->chandef = wdev->preset_chandef;
        }
 
-       if (!setup->channel) {
+       if (!setup->chandef.chan) {
                /* if we don't have that either, use the first usable channel */
                enum ieee80211_band band;
 
@@ -137,26 +134,25 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
                                                   IEEE80211_CHAN_DISABLED |
                                                   IEEE80211_CHAN_RADAR))
                                        continue;
-                               setup->channel = chan;
+                               setup->chandef.chan = chan;
                                break;
                        }
 
-                       if (setup->channel)
+                       if (setup->chandef.chan)
                                break;
                }
 
                /* no usable channel ... */
-               if (!setup->channel)
+               if (!setup->chandef.chan)
                        return -EINVAL;
 
-               setup->channel_type = NL80211_CHAN_NO_HT;
+               setup->chandef.width = NL80211_CHAN_WIDTH_20_NOHT;;
        }
 
-       if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, setup->channel,
-                                         setup->channel_type))
+       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &setup->chandef))
                return -EINVAL;
 
-       err = cfg80211_can_use_chan(rdev, wdev, setup->channel,
+       err = cfg80211_can_use_chan(rdev, wdev, setup->chandef.chan,
                                    CHAN_MODE_SHARED);
        if (err)
                return err;
@@ -165,7 +161,7 @@ int __cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
        if (!err) {
                memcpy(wdev->ssid, setup->mesh_id, setup->mesh_id_len);
                wdev->mesh_id_len = setup->mesh_id_len;
-               wdev->channel = setup->channel;
+               wdev->channel = setup->chandef.chan;
        }
 
        return err;
@@ -188,20 +184,12 @@ int cfg80211_join_mesh(struct cfg80211_registered_device *rdev,
        return err;
 }
 
-int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
-                          struct wireless_dev *wdev, int freq,
-                          enum nl80211_channel_type channel_type)
+int cfg80211_set_mesh_channel(struct cfg80211_registered_device *rdev,
+                             struct wireless_dev *wdev,
+                             struct cfg80211_chan_def *chandef)
 {
-       struct ieee80211_channel *channel;
        int err;
 
-       channel = rdev_freq_to_chan(rdev, freq, channel_type);
-       if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
-                                                     channel,
-                                                     channel_type)) {
-               return -EINVAL;
-       }
-
        /*
         * Workaround for libertas (only!), it puts the interface
         * into mesh mode but doesn't implement join_mesh. Instead,
@@ -210,21 +198,21 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
         * compatible with 802.11 mesh.
         */
        if (rdev->ops->libertas_set_mesh_channel) {
-               if (channel_type != NL80211_CHAN_NO_HT)
+               if (chandef->width != NL80211_CHAN_WIDTH_20_NOHT)
                        return -EINVAL;
 
                if (!netif_running(wdev->netdev))
                        return -ENETDOWN;
 
-               err = cfg80211_can_use_chan(rdev, wdev, channel,
+               err = cfg80211_can_use_chan(rdev, wdev, chandef->chan,
                                            CHAN_MODE_SHARED);
                if (err)
                        return err;
 
                err = rdev_libertas_set_mesh_channel(rdev, wdev->netdev,
-                                                    channel);
+                                                    chandef->chan);
                if (!err)
-                       wdev->channel = channel;
+                       wdev->channel = chandef->chan;
 
                return err;
        }
@@ -232,8 +220,7 @@ int cfg80211_set_mesh_freq(struct cfg80211_registered_device *rdev,
        if (wdev->mesh_id_len)
                return -EBUSY;
 
-       wdev->preset_chan = channel;
-       wdev->preset_chantype = channel_type;
+       wdev->preset_chandef = *chandef;
        return 0;
 }
 
index 4bfd14f7c5920c239f1802d6ddb131cd53f173db..5e8123ee63fd316d48e224fe65b8336300ec2b79 100644 (file)
@@ -579,31 +579,25 @@ void cfg80211_mlme_down(struct cfg80211_registered_device *rdev,
 
 void cfg80211_ready_on_channel(struct wireless_dev *wdev, u64 cookie,
                               struct ieee80211_channel *chan,
-                              enum nl80211_channel_type channel_type,
                               unsigned int duration, gfp_t gfp)
 {
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       trace_cfg80211_ready_on_channel(wdev, cookie, chan, channel_type,
-                                       duration);
-       nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, channel_type,
-                                      duration, gfp);
+       trace_cfg80211_ready_on_channel(wdev, cookie, chan, duration);
+       nl80211_send_remain_on_channel(rdev, wdev, cookie, chan, duration, gfp);
 }
 EXPORT_SYMBOL(cfg80211_ready_on_channel);
 
 void cfg80211_remain_on_channel_expired(struct wireless_dev *wdev, u64 cookie,
                                        struct ieee80211_channel *chan,
-                                       enum nl80211_channel_type channel_type,
                                        gfp_t gfp)
 {
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
 
-       trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan,
-                                               channel_type);
-       nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan,
-                                             channel_type, gfp);
+       trace_cfg80211_ready_on_channel_expired(wdev, cookie, chan);
+       nl80211_send_remain_on_channel_cancel(rdev, wdev, cookie, chan, gfp);
 }
 EXPORT_SYMBOL(cfg80211_remain_on_channel_expired);
 
@@ -758,10 +752,8 @@ void cfg80211_mlme_purge_registrations(struct wireless_dev *wdev)
 int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
                          struct wireless_dev *wdev,
                          struct ieee80211_channel *chan, bool offchan,
-                         enum nl80211_channel_type channel_type,
-                         bool channel_type_valid, unsigned int wait,
-                         const u8 *buf, size_t len, bool no_cck,
-                         bool dont_wait_for_ack, u64 *cookie)
+                         unsigned int wait, const u8 *buf, size_t len,
+                         bool no_cck, bool dont_wait_for_ack, u64 *cookie)
 {
        const struct ieee80211_mgmt *mgmt;
        u16 stype;
@@ -855,7 +847,6 @@ int cfg80211_mlme_mgmt_tx(struct cfg80211_registered_device *rdev,
 
        /* Transmit the Action frame as requested by user space */
        return rdev_mgmt_tx(rdev, wdev, chan, offchan,
-                           channel_type, channel_type_valid,
                            wait, buf, len, no_cck, dont_wait_for_ack,
                            cookie);
 }
@@ -997,15 +988,14 @@ void cfg80211_pmksa_candidate_notify(struct net_device *dev, int index,
 }
 EXPORT_SYMBOL(cfg80211_pmksa_candidate_notify);
 
-void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
-                              enum nl80211_channel_type type)
+void cfg80211_ch_switch_notify(struct net_device *dev,
+                              struct cfg80211_chan_def *chandef)
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct wiphy *wiphy = wdev->wiphy;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
-       struct ieee80211_channel *chan;
 
-       trace_cfg80211_ch_switch_notify(dev, freq, type);
+       trace_cfg80211_ch_switch_notify(dev, chandef);
 
        wdev_lock(wdev);
 
@@ -1013,12 +1003,8 @@ void cfg80211_ch_switch_notify(struct net_device *dev, int freq,
                    wdev->iftype != NL80211_IFTYPE_P2P_GO))
                goto out;
 
-       chan = rdev_freq_to_chan(rdev, freq, type);
-       if (WARN_ON(!chan))
-               goto out;
-
-       wdev->channel = chan;
-       nl80211_ch_switch_notify(rdev, dev, freq, type, GFP_KERNEL);
+       wdev->channel = chandef->chan;
+       nl80211_ch_switch_notify(rdev, dev, chandef, GFP_KERNEL);
 out:
        wdev_unlock(wdev);
        return;
index 8c0857815a900ab8aeb56791585739bb37650233..d038fa45ecd1bf38a5ee3b83a51b5dde9df40744 100644 (file)
@@ -223,8 +223,13 @@ static const struct nla_policy nl80211_policy[NL80211_ATTR_MAX+1] = {
        [NL80211_ATTR_WIPHY_NAME] = { .type = NLA_NUL_STRING,
                                      .len = 20-1 },
        [NL80211_ATTR_WIPHY_TXQ_PARAMS] = { .type = NLA_NESTED },
+
        [NL80211_ATTR_WIPHY_FREQ] = { .type = NLA_U32 },
        [NL80211_ATTR_WIPHY_CHANNEL_TYPE] = { .type = NLA_U32 },
+       [NL80211_ATTR_CHANNEL_WIDTH] = { .type = NLA_U32 },
+       [NL80211_ATTR_CENTER_FREQ1] = { .type = NLA_U32 },
+       [NL80211_ATTR_CENTER_FREQ2] = { .type = NLA_U32 },
+
        [NL80211_ATTR_WIPHY_RETRY_SHORT] = { .type = NLA_U8 },
        [NL80211_ATTR_WIPHY_RETRY_LONG] = { .type = NLA_U8 },
        [NL80211_ATTR_WIPHY_FRAG_THRESHOLD] = { .type = NLA_U32 },
@@ -1110,6 +1115,7 @@ static int nl80211_send_wiphy(struct sk_buff *msg, u32 portid, u32 seq, int flag
                        goto nla_put_failure;
        }
        CMD(start_p2p_device, START_P2P_DEVICE);
+       CMD(set_mcast_rate, SET_MCAST_RATE);
 
 #ifdef CONFIG_NL80211_TESTMODE
        CMD(testmode_cmd, TESTMODE);
@@ -1359,51 +1365,139 @@ static bool nl80211_can_set_dev_channel(struct wireless_dev *wdev)
                wdev->iftype == NL80211_IFTYPE_P2P_GO;
 }
 
-static bool nl80211_valid_channel_type(struct genl_info *info,
-                                      enum nl80211_channel_type *channel_type)
+static int nl80211_parse_chandef(struct cfg80211_registered_device *rdev,
+                                struct genl_info *info,
+                                struct cfg80211_chan_def *chandef)
 {
-       enum nl80211_channel_type tmp;
+       struct ieee80211_sta_ht_cap *ht_cap;
+       struct ieee80211_sta_vht_cap *vht_cap;
+       u32 control_freq, width;
 
-       if (!info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE])
-               return false;
+       if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
+               return -EINVAL;
 
-       tmp = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
-       if (tmp != NL80211_CHAN_NO_HT &&
-           tmp != NL80211_CHAN_HT20 &&
-           tmp != NL80211_CHAN_HT40PLUS &&
-           tmp != NL80211_CHAN_HT40MINUS)
-               return false;
+       control_freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
 
-       if (channel_type)
-               *channel_type = tmp;
+       chandef->chan = ieee80211_get_channel(&rdev->wiphy, control_freq);
+       chandef->width = NL80211_CHAN_WIDTH_20_NOHT;
+       chandef->center_freq1 = control_freq;
+       chandef->center_freq2 = 0;
 
-       return true;
+       /* Primary channel not allowed */
+       if (!chandef->chan || chandef->chan->flags & IEEE80211_CHAN_DISABLED)
+               return -EINVAL;
+
+       if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
+               enum nl80211_channel_type chantype;
+
+               chantype = nla_get_u32(
+                               info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]);
+
+               switch (chantype) {
+               case NL80211_CHAN_NO_HT:
+               case NL80211_CHAN_HT20:
+               case NL80211_CHAN_HT40PLUS:
+               case NL80211_CHAN_HT40MINUS:
+                       cfg80211_chandef_create(chandef, chandef->chan,
+                                               chantype);
+                       break;
+               default:
+                       return -EINVAL;
+               }
+       } else if (info->attrs[NL80211_ATTR_CHANNEL_WIDTH]) {
+               chandef->width =
+                       nla_get_u32(info->attrs[NL80211_ATTR_CHANNEL_WIDTH]);
+               if (info->attrs[NL80211_ATTR_CENTER_FREQ1])
+                       chandef->center_freq1 =
+                               nla_get_u32(
+                                       info->attrs[NL80211_ATTR_CENTER_FREQ1]);
+               if (info->attrs[NL80211_ATTR_CENTER_FREQ2])
+                       chandef->center_freq2 =
+                               nla_get_u32(
+                                       info->attrs[NL80211_ATTR_CENTER_FREQ2]);
+       }
+
+       ht_cap = &rdev->wiphy.bands[chandef->chan->band]->ht_cap;
+       vht_cap = &rdev->wiphy.bands[chandef->chan->band]->vht_cap;
+
+       if (!cfg80211_chan_def_valid(chandef))
+               return -EINVAL;
+
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_20:
+               if (!ht_cap->ht_supported)
+                       return -EINVAL;
+       case NL80211_CHAN_WIDTH_20_NOHT:
+               width = 20;
+               break;
+       case NL80211_CHAN_WIDTH_40:
+               width = 40;
+               /* quick early regulatory check */
+               if (chandef->center_freq1 < control_freq &&
+                   chandef->chan->flags & IEEE80211_CHAN_NO_HT40MINUS)
+                       return -EINVAL;
+               if (chandef->center_freq1 > control_freq &&
+                   chandef->chan->flags & IEEE80211_CHAN_NO_HT40PLUS)
+                       return -EINVAL;
+               if (!ht_cap->ht_supported)
+                       return -EINVAL;
+               if (!(ht_cap->cap & IEEE80211_HT_CAP_SUP_WIDTH_20_40) ||
+                   ht_cap->cap & IEEE80211_HT_CAP_40MHZ_INTOLERANT)
+                       return -EINVAL;
+               break;
+       case NL80211_CHAN_WIDTH_80:
+               width = 80;
+               if (!vht_cap->vht_supported)
+                       return -EINVAL;
+               break;
+       case NL80211_CHAN_WIDTH_80P80:
+               width = 80;
+               if (!vht_cap->vht_supported)
+                       return -EINVAL;
+               if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160_80PLUS80MHZ))
+                       return -EINVAL;
+               break;
+       case NL80211_CHAN_WIDTH_160:
+               width = 160;
+               if (!vht_cap->vht_supported)
+                       return -EINVAL;
+               if (!(vht_cap->cap & IEEE80211_VHT_CAP_SUPP_CHAN_WIDTH_160MHZ))
+                       return -EINVAL;
+               break;
+       default:
+               return -EINVAL;
+       }
+
+       if (!cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq1,
+                                        width, IEEE80211_CHAN_DISABLED))
+               return -EINVAL;
+       if (chandef->center_freq2 &&
+           !cfg80211_secondary_chans_ok(&rdev->wiphy, chandef->center_freq2,
+                                        width, IEEE80211_CHAN_DISABLED))
+               return -EINVAL;
+
+       /* TODO: missing regulatory check on bandwidth */
+
+       return 0;
 }
 
 static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
                                 struct wireless_dev *wdev,
                                 struct genl_info *info)
 {
-       struct ieee80211_channel *channel;
-       enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-       u32 freq;
+       struct cfg80211_chan_def chandef;
        int result;
        enum nl80211_iftype iftype = NL80211_IFTYPE_MONITOR;
 
        if (wdev)
                iftype = wdev->iftype;
 
-       if (!info->attrs[NL80211_ATTR_WIPHY_FREQ])
-               return -EINVAL;
-
        if (!nl80211_can_set_dev_channel(wdev))
                return -EOPNOTSUPP;
 
-       if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
-           !nl80211_valid_channel_type(info, &channel_type))
-               return -EINVAL;
-
-       freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
+       result = nl80211_parse_chandef(rdev, info, &chandef);
+       if (result)
+               return result;
 
        mutex_lock(&rdev->devlist_mtx);
        switch (iftype) {
@@ -1413,22 +1507,18 @@ static int __nl80211_set_channel(struct cfg80211_registered_device *rdev,
                        result = -EBUSY;
                        break;
                }
-               channel = rdev_freq_to_chan(rdev, freq, channel_type);
-               if (!channel || !cfg80211_can_beacon_sec_chan(&rdev->wiphy,
-                                                             channel,
-                                                             channel_type)) {
+               if (!cfg80211_reg_can_beacon(&rdev->wiphy, &chandef)) {
                        result = -EINVAL;
                        break;
                }
-               wdev->preset_chan = channel;
-               wdev->preset_chantype = channel_type;
+               wdev->preset_chandef = chandef;
                result = 0;
                break;
        case NL80211_IFTYPE_MESH_POINT:
-               result = cfg80211_set_mesh_freq(rdev, wdev, freq, channel_type);
+               result = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
                break;
        case NL80211_IFTYPE_MONITOR:
-               result = cfg80211_set_monitor_channel(rdev, freq, channel_type);
+               result = cfg80211_set_monitor_channel(rdev, &chandef);
                break;
        default:
                result = -EINVAL;
@@ -1516,10 +1606,8 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                result = 0;
 
                mutex_lock(&rdev->mtx);
-       } else if (nl80211_can_set_dev_channel(netdev->ieee80211_ptr))
+       } else
                wdev = netdev->ieee80211_ptr;
-       else
-               wdev = NULL;
 
        /*
         * end workaround code, by now the rdev is available
@@ -1579,15 +1667,21 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-               result = __nl80211_set_channel(rdev, wdev, info);
+               result = __nl80211_set_channel(rdev,
+                               nl80211_can_set_dev_channel(wdev) ? wdev : NULL,
+                               info);
                if (result)
                        goto bad_res;
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_TX_POWER_SETTING]) {
+               struct wireless_dev *txp_wdev = wdev;
                enum nl80211_tx_power_setting type;
                int idx, mbm = 0;
 
+               if (!(rdev->wiphy.features & NL80211_FEATURE_VIF_TXPOWER))
+                       txp_wdev = NULL;
+
                if (!rdev->ops->set_tx_power) {
                        result = -EOPNOTSUPP;
                        goto bad_res;
@@ -1607,7 +1701,7 @@ static int nl80211_set_wiphy(struct sk_buff *skb, struct genl_info *info)
                        mbm = nla_get_u32(info->attrs[idx]);
                }
 
-               result = rdev_set_tx_power(rdev, type, mbm);
+               result = rdev_set_tx_power(rdev, txp_wdev, type, mbm);
                if (result)
                        goto bad_res;
        }
@@ -1744,6 +1838,35 @@ static inline u64 wdev_id(struct wireless_dev *wdev)
               ((u64)wiphy_to_dev(wdev->wiphy)->wiphy_idx << 32);
 }
 
+static int nl80211_send_chandef(struct sk_buff *msg,
+                                struct cfg80211_chan_def *chandef)
+{
+       WARN_ON(!cfg80211_chan_def_valid(chandef));
+
+       if (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
+                       chandef->chan->center_freq))
+               return -ENOBUFS;
+       switch (chandef->width) {
+       case NL80211_CHAN_WIDTH_20_NOHT:
+       case NL80211_CHAN_WIDTH_20:
+       case NL80211_CHAN_WIDTH_40:
+               if (nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+                               cfg80211_get_chandef_type(chandef)))
+                       return -ENOBUFS;
+               break;
+       default:
+               break;
+       }
+       if (nla_put_u32(msg, NL80211_ATTR_CHANNEL_WIDTH, chandef->width))
+               return -ENOBUFS;
+       if (nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ1, chandef->center_freq1))
+               return -ENOBUFS;
+       if (chandef->center_freq2 &&
+           nla_put_u32(msg, NL80211_ATTR_CENTER_FREQ2, chandef->center_freq2))
+               return -ENOBUFS;
+       return 0;
+}
+
 static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flags,
                              struct cfg80211_registered_device *rdev,
                              struct wireless_dev *wdev)
@@ -1770,15 +1893,18 @@ static int nl80211_send_iface(struct sk_buff *msg, u32 portid, u32 seq, int flag
                goto nla_put_failure;
 
        if (rdev->ops->get_channel) {
-               struct ieee80211_channel *chan;
-               enum nl80211_channel_type channel_type;
-
-               chan = rdev_get_channel(rdev, wdev, &channel_type);
-               if (chan &&
-                   (nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ,
-                                chan->center_freq) ||
-                    nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
-                                channel_type)))
+               int ret;
+               struct cfg80211_chan_def chandef;
+
+               ret = rdev_get_channel(rdev, wdev, &chandef);
+               if (ret == 0) {
+                       if (nl80211_send_chandef(msg, &chandef))
+                               goto nla_put_failure;
+               }
+       }
+
+       if (wdev->ssid_len) {
+               if (nla_put(msg, NL80211_ATTR_SSID, wdev->ssid_len, wdev->ssid))
                        goto nla_put_failure;
        }
 
@@ -2482,11 +2608,10 @@ static bool nl80211_get_ap_channel(struct cfg80211_registered_device *rdev,
                    wdev->iftype != NL80211_IFTYPE_P2P_GO)
                        continue;
 
-               if (!wdev->preset_chan)
+               if (!wdev->preset_chandef.chan)
                        continue;
 
-               params->channel = wdev->preset_chan;
-               params->channel_type = wdev->preset_chantype;
+               params->chandef = wdev->preset_chandef;
                ret = true;
                break;
        }
@@ -2608,30 +2733,19 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-               enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-
-               if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
-                   !nl80211_valid_channel_type(info, &channel_type))
-                       return -EINVAL;
-
-               params.channel = rdev_freq_to_chan(rdev,
-                       nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
-                       channel_type);
-               if (!params.channel)
-                       return -EINVAL;
-               params.channel_type = channel_type;
-       } else if (wdev->preset_chan) {
-               params.channel = wdev->preset_chan;
-               params.channel_type = wdev->preset_chantype;
+               err = nl80211_parse_chandef(rdev, info, &params.chandef);
+               if (err)
+                       return err;
+       } else if (wdev->preset_chandef.chan) {
+               params.chandef = wdev->preset_chandef;
        } else if (!nl80211_get_ap_channel(rdev, &params))
                return -EINVAL;
 
-       if (!cfg80211_can_beacon_sec_chan(&rdev->wiphy, params.channel,
-                                         params.channel_type))
+       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &params.chandef))
                return -EINVAL;
 
        mutex_lock(&rdev->devlist_mtx);
-       err = cfg80211_can_use_chan(rdev, wdev, params.channel,
+       err = cfg80211_can_use_chan(rdev, wdev, params.chandef.chan,
                                    CHAN_MODE_SHARED);
        mutex_unlock(&rdev->devlist_mtx);
 
@@ -2640,10 +2754,11 @@ static int nl80211_start_ap(struct sk_buff *skb, struct genl_info *info)
 
        err = rdev_start_ap(rdev, dev, &params);
        if (!err) {
-               wdev->preset_chan = params.channel;
-               wdev->preset_chantype = params.channel_type;
+               wdev->preset_chandef = params.chandef;
                wdev->beacon_interval = params.beacon_interval;
-               wdev->channel = params.channel;
+               wdev->channel = params.chandef.chan;
+               wdev->ssid_len = params.ssid_len;
+               memcpy(wdev->ssid, params.ssid, wdev->ssid_len);
        }
        return err;
 }
@@ -2775,29 +2890,52 @@ static bool nl80211_put_sta_rate(struct sk_buff *msg, struct rate_info *info,
 
        rate = nla_nest_start(msg, attr);
        if (!rate)
-               goto nla_put_failure;
+               return false;
 
        /* cfg80211_calculate_bitrate will return 0 for mcs >= 32 */
        bitrate = cfg80211_calculate_bitrate(info);
        /* report 16-bit bitrate only if we can */
        bitrate_compat = bitrate < (1UL << 16) ? bitrate : 0;
-       if ((bitrate > 0 &&
-            nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate)) ||
-           (bitrate_compat > 0 &&
-            nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat)) ||
-           ((info->flags & RATE_INFO_FLAGS_MCS) &&
-            nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs)) ||
-           ((info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH) &&
-            nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH)) ||
-           ((info->flags & RATE_INFO_FLAGS_SHORT_GI) &&
-            nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI)))
-               goto nla_put_failure;
+       if (bitrate > 0 &&
+           nla_put_u32(msg, NL80211_RATE_INFO_BITRATE32, bitrate))
+               return false;
+       if (bitrate_compat > 0 &&
+           nla_put_u16(msg, NL80211_RATE_INFO_BITRATE, bitrate_compat))
+               return false;
+
+       if (info->flags & RATE_INFO_FLAGS_MCS) {
+               if (nla_put_u8(msg, NL80211_RATE_INFO_MCS, info->mcs))
+                       return false;
+               if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+                   nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+                       return false;
+               if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+                   nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+                       return false;
+       } else if (info->flags & RATE_INFO_FLAGS_VHT_MCS) {
+               if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_MCS, info->mcs))
+                       return false;
+               if (nla_put_u8(msg, NL80211_RATE_INFO_VHT_NSS, info->nss))
+                       return false;
+               if (info->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH &&
+                   nla_put_flag(msg, NL80211_RATE_INFO_40_MHZ_WIDTH))
+                       return false;
+               if (info->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH &&
+                   nla_put_flag(msg, NL80211_RATE_INFO_80_MHZ_WIDTH))
+                       return false;
+               if (info->flags & RATE_INFO_FLAGS_80P80_MHZ_WIDTH &&
+                   nla_put_flag(msg, NL80211_RATE_INFO_80P80_MHZ_WIDTH))
+                       return false;
+               if (info->flags & RATE_INFO_FLAGS_160_MHZ_WIDTH &&
+                   nla_put_flag(msg, NL80211_RATE_INFO_160_MHZ_WIDTH))
+                       return false;
+               if (info->flags & RATE_INFO_FLAGS_SHORT_GI &&
+                   nla_put_flag(msg, NL80211_RATE_INFO_SHORT_GI))
+                       return false;
+       }
 
        nla_nest_end(msg, rate);
        return true;
-
-nla_put_failure:
-       return false;
 }
 
 static int nl80211_send_station(struct sk_buff *msg, u32 portid, u32 seq,
@@ -5318,8 +5456,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
        if (!is_valid_ie_attr(info->attrs[NL80211_ATTR_IE]))
                return -EINVAL;
 
-       if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
-           !info->attrs[NL80211_ATTR_SSID] ||
+       if (!info->attrs[NL80211_ATTR_SSID] ||
            !nla_len(info->attrs[NL80211_ATTR_SSID]))
                return -EINVAL;
 
@@ -5354,35 +5491,17 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                ibss.ie_len = nla_len(info->attrs[NL80211_ATTR_IE]);
        }
 
-       if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
-               enum nl80211_channel_type channel_type;
-
-               if (!nl80211_valid_channel_type(info, &channel_type))
-                       return -EINVAL;
-
-               if (channel_type != NL80211_CHAN_NO_HT &&
-                   !(wiphy->features & NL80211_FEATURE_HT_IBSS))
-                       return -EINVAL;
-
-               ibss.channel_type = channel_type;
-       } else {
-               ibss.channel_type = NL80211_CHAN_NO_HT;
-       }
+       err = nl80211_parse_chandef(rdev, info, &ibss.chandef);
+       if (err)
+               return err;
 
-       ibss.channel = rdev_freq_to_chan(rdev,
-               nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
-               ibss.channel_type);
-       if (!ibss.channel ||
-           ibss.channel->flags & IEEE80211_CHAN_NO_IBSS ||
-           ibss.channel->flags & IEEE80211_CHAN_DISABLED)
+       if (!cfg80211_reg_can_beacon(&rdev->wiphy, &ibss.chandef))
                return -EINVAL;
 
-       /* Both channels should be able to initiate communication */
-       if ((ibss.channel_type == NL80211_CHAN_HT40PLUS ||
-            ibss.channel_type == NL80211_CHAN_HT40MINUS) &&
-           !cfg80211_can_beacon_sec_chan(&rdev->wiphy, ibss.channel,
-                                         ibss.channel_type))
+       if (ibss.chandef.width > NL80211_CHAN_WIDTH_40)
                return -EINVAL;
+       if (ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT &&
+           !(rdev->wiphy.features & NL80211_FEATURE_HT_IBSS))
 
        ibss.channel_fixed = !!info->attrs[NL80211_ATTR_FREQ_FIXED];
        ibss.privacy = !!info->attrs[NL80211_ATTR_PRIVACY];
@@ -5393,7 +5512,7 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                int n_rates =
                        nla_len(info->attrs[NL80211_ATTR_BSS_BASIC_RATES]);
                struct ieee80211_supported_band *sband =
-                       wiphy->bands[ibss.channel->band];
+                       wiphy->bands[ibss.chandef.chan->band];
 
                err = ieee80211_get_ratemask(sband, rates, n_rates,
                                             &ibss.basic_rates);
@@ -5415,7 +5534,8 @@ static int nl80211_join_ibss(struct sk_buff *skb, struct genl_info *info)
                if (IS_ERR(connkeys))
                        return PTR_ERR(connkeys);
 
-               if ((ibss.channel_type != NL80211_CHAN_NO_HT) && no_ht) {
+               if ((ibss.chandef.width != NL80211_CHAN_WIDTH_20_NOHT) &&
+                   no_ht) {
                        kfree(connkeys);
                        return -EINVAL;
                }
@@ -5444,6 +5564,36 @@ static int nl80211_leave_ibss(struct sk_buff *skb, struct genl_info *info)
        return cfg80211_leave_ibss(rdev, dev, false);
 }
 
+static int nl80211_set_mcast_rate(struct sk_buff *skb, struct genl_info *info)
+{
+       struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct net_device *dev = info->user_ptr[1];
+       int mcast_rate[IEEE80211_NUM_BANDS];
+       u32 nla_rate;
+       int err;
+
+       if (dev->ieee80211_ptr->iftype != NL80211_IFTYPE_ADHOC &&
+           dev->ieee80211_ptr->iftype != NL80211_IFTYPE_MESH_POINT)
+               return -EOPNOTSUPP;
+
+       if (!rdev->ops->set_mcast_rate)
+               return -EOPNOTSUPP;
+
+       memset(mcast_rate, 0, sizeof(mcast_rate));
+
+       if (!info->attrs[NL80211_ATTR_MCAST_RATE])
+               return -EINVAL;
+
+       nla_rate = nla_get_u32(info->attrs[NL80211_ATTR_MCAST_RATE]);
+       if (!nl80211_parse_mcast_rate(rdev, mcast_rate, nla_rate))
+               return -EINVAL;
+
+       err = rdev->ops->set_mcast_rate(&rdev->wiphy, dev, mcast_rate);
+
+       return err;
+}
+
+
 #ifdef CONFIG_NL80211_TESTMODE
 static struct genl_multicast_group nl80211_testmode_mcgrp = {
        .name = "testmode",
@@ -5906,12 +6056,11 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct wireless_dev *wdev = info->user_ptr[1];
-       struct ieee80211_channel *chan;
+       struct cfg80211_chan_def chandef;
        struct sk_buff *msg;
        void *hdr;
        u64 cookie;
-       enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-       u32 freq, duration;
+       u32 duration;
        int err;
 
        if (!info->attrs[NL80211_ATTR_WIPHY_FREQ] ||
@@ -5932,14 +6081,9 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
            duration > rdev->wiphy.max_remain_on_channel_duration)
                return -EINVAL;
 
-       if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
-           !nl80211_valid_channel_type(info, &channel_type))
-               return -EINVAL;
-
-       freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
-       chan = rdev_freq_to_chan(rdev, freq, channel_type);
-       if (chan == NULL)
-               return -EINVAL;
+       err = nl80211_parse_chandef(rdev, info, &chandef);
+       if (err)
+               return err;
 
        msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
        if (!msg)
@@ -5953,8 +6097,8 @@ static int nl80211_remain_on_channel(struct sk_buff *skb,
                goto free_msg;
        }
 
-       err = rdev_remain_on_channel(rdev, wdev, chan, channel_type, duration,
-                                    &cookie);
+       err = rdev_remain_on_channel(rdev, wdev, chandef.chan,
+                                    duration, &cookie);
 
        if (err)
                goto free_msg;
@@ -6173,10 +6317,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
        struct wireless_dev *wdev = info->user_ptr[1];
-       struct ieee80211_channel *chan;
-       enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-       bool channel_type_valid = false;
-       u32 freq;
+       struct cfg80211_chan_def chandef;
        int err;
        void *hdr = NULL;
        u64 cookie;
@@ -6186,8 +6327,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 
        dont_wait_for_ack = info->attrs[NL80211_ATTR_DONT_WAIT_FOR_ACK];
 
-       if (!info->attrs[NL80211_ATTR_FRAME] ||
-           !info->attrs[NL80211_ATTR_WIPHY_FREQ])
+       if (!info->attrs[NL80211_ATTR_FRAME])
                return -EINVAL;
 
        if (!rdev->ops->mgmt_tx)
@@ -6222,12 +6362,6 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 
        }
 
-       if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE]) {
-               if (!nl80211_valid_channel_type(info, &channel_type))
-                       return -EINVAL;
-               channel_type_valid = true;
-       }
-
        offchan = info->attrs[NL80211_ATTR_OFFCHANNEL_TX_OK];
 
        if (offchan && !(rdev->wiphy.flags & WIPHY_FLAG_OFFCHAN_TX))
@@ -6235,10 +6369,9 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
 
        no_cck = nla_get_flag(info->attrs[NL80211_ATTR_TX_NO_CCK_RATE]);
 
-       freq = nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]);
-       chan = rdev_freq_to_chan(rdev, freq, channel_type);
-       if (chan == NULL)
-               return -EINVAL;
+       err = nl80211_parse_chandef(rdev, info, &chandef);
+       if (err)
+               return err;
 
        if (!dont_wait_for_ack) {
                msg = nlmsg_new(NLMSG_DEFAULT_SIZE, GFP_KERNEL);
@@ -6254,8 +6387,7 @@ static int nl80211_tx_mgmt(struct sk_buff *skb, struct genl_info *info)
                }
        }
 
-       err = cfg80211_mlme_mgmt_tx(rdev, wdev, chan, offchan, channel_type,
-                                   channel_type_valid, wait,
+       err = cfg80211_mlme_mgmt_tx(rdev, wdev, chandef.chan, offchan, wait,
                                    nla_data(info->attrs[NL80211_ATTR_FRAME]),
                                    nla_len(info->attrs[NL80211_ATTR_FRAME]),
                                    no_cck, dont_wait_for_ack, &cookie);
@@ -6519,21 +6651,12 @@ static int nl80211_join_mesh(struct sk_buff *skb, struct genl_info *info)
        }
 
        if (info->attrs[NL80211_ATTR_WIPHY_FREQ]) {
-               enum nl80211_channel_type channel_type = NL80211_CHAN_NO_HT;
-
-               if (info->attrs[NL80211_ATTR_WIPHY_CHANNEL_TYPE] &&
-                   !nl80211_valid_channel_type(info, &channel_type))
-                       return -EINVAL;
-
-               setup.channel = rdev_freq_to_chan(rdev,
-                       nla_get_u32(info->attrs[NL80211_ATTR_WIPHY_FREQ]),
-                       channel_type);
-               if (!setup.channel)
-                       return -EINVAL;
-               setup.channel_type = channel_type;
+               err = nl80211_parse_chandef(rdev, info, &setup.chandef);
+               if (err)
+                       return err;
        } else {
                /* cfg80211_join_mesh() will sort it out */
-               setup.channel = NULL;
+               setup.chandef.chan = NULL;
        }
 
        return cfg80211_join_mesh(rdev, dev, &setup, &cfg);
@@ -6899,16 +7022,35 @@ static int nl80211_probe_client(struct sk_buff *skb,
 static int nl80211_register_beacons(struct sk_buff *skb, struct genl_info *info)
 {
        struct cfg80211_registered_device *rdev = info->user_ptr[0];
+       struct cfg80211_beacon_registration *reg, *nreg;
+       int rv;
 
        if (!(rdev->wiphy.flags & WIPHY_FLAG_REPORTS_OBSS))
                return -EOPNOTSUPP;
 
-       if (rdev->ap_beacons_nlportid)
-               return -EBUSY;
+       nreg = kzalloc(sizeof(*nreg), GFP_KERNEL);
+       if (!nreg)
+               return -ENOMEM;
 
-       rdev->ap_beacons_nlportid = info->snd_portid;
+       /* First, check if already registered. */
+       spin_lock_bh(&rdev->beacon_registrations_lock);
+       list_for_each_entry(reg, &rdev->beacon_registrations, list) {
+               if (reg->nlportid == info->snd_portid) {
+                       rv = -EALREADY;
+                       goto out_err;
+               }
+       }
+       /* Add it to the list */
+       nreg->nlportid = info->snd_portid;
+       list_add(&nreg->list, &rdev->beacon_registrations);
+
+       spin_unlock_bh(&rdev->beacon_registrations_lock);
 
        return 0;
+out_err:
+       spin_unlock_bh(&rdev->beacon_registrations_lock);
+       kfree(nreg);
+       return rv;
 }
 
 static int nl80211_start_p2p_device(struct sk_buff *skb, struct genl_info *info)
@@ -7625,6 +7767,14 @@ static struct genl_ops nl80211_ops[] = {
                .internal_flags = NL80211_FLAG_NEED_WDEV_UP |
                                  NL80211_FLAG_NEED_RTNL,
        },
+       {
+               .cmd = NL80211_CMD_SET_MCAST_RATE,
+               .doit = nl80211_set_mcast_rate,
+               .policy = nl80211_policy,
+               .flags = GENL_ADMIN_PERM,
+               .internal_flags = NL80211_FLAG_NEED_NETDEV |
+                                 NL80211_FLAG_NEED_RTNL,
+       },
 };
 
 static struct genl_multicast_group nl80211_mlme_mcgrp = {
@@ -8326,7 +8476,6 @@ static void nl80211_send_remain_on_chan_event(
        int cmd, struct cfg80211_registered_device *rdev,
        struct wireless_dev *wdev, u64 cookie,
        struct ieee80211_channel *chan,
-       enum nl80211_channel_type channel_type,
        unsigned int duration, gfp_t gfp)
 {
        struct sk_buff *msg;
@@ -8347,7 +8496,8 @@ static void nl80211_send_remain_on_chan_event(
                                         wdev->netdev->ifindex)) ||
            nla_put_u64(msg, NL80211_ATTR_WDEV, wdev_id(wdev)) ||
            nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, chan->center_freq) ||
-           nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, channel_type) ||
+           nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE,
+                       NL80211_CHAN_NO_HT) ||
            nla_put_u64(msg, NL80211_ATTR_COOKIE, cookie))
                goto nla_put_failure;
 
@@ -8369,23 +8519,20 @@ static void nl80211_send_remain_on_chan_event(
 void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
                                    struct wireless_dev *wdev, u64 cookie,
                                    struct ieee80211_channel *chan,
-                                   enum nl80211_channel_type channel_type,
                                    unsigned int duration, gfp_t gfp)
 {
        nl80211_send_remain_on_chan_event(NL80211_CMD_REMAIN_ON_CHANNEL,
                                          rdev, wdev, cookie, chan,
-                                         channel_type, duration, gfp);
+                                         duration, gfp);
 }
 
 void nl80211_send_remain_on_channel_cancel(
        struct cfg80211_registered_device *rdev,
        struct wireless_dev *wdev,
-       u64 cookie, struct ieee80211_channel *chan,
-       enum nl80211_channel_type channel_type, gfp_t gfp)
+       u64 cookie, struct ieee80211_channel *chan, gfp_t gfp)
 {
        nl80211_send_remain_on_chan_event(NL80211_CMD_CANCEL_REMAIN_ON_CHANNEL,
-                                         rdev, wdev, cookie, chan,
-                                         channel_type, 0, gfp);
+                                         rdev, wdev, cookie, chan, 0, gfp);
 }
 
 void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
@@ -8741,8 +8888,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
 }
 
 void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
-                             struct net_device *netdev, int freq,
-                             enum nl80211_channel_type type, gfp_t gfp)
+                             struct net_device *netdev,
+                             struct cfg80211_chan_def *chandef, gfp_t gfp)
 {
        struct sk_buff *msg;
        void *hdr;
@@ -8757,9 +8904,10 @@ void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
                return;
        }
 
-       if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex) ||
-           nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq) ||
-           nla_put_u32(msg, NL80211_ATTR_WIPHY_CHANNEL_TYPE, type))
+       if (nla_put_u32(msg, NL80211_ATTR_IFINDEX, netdev->ifindex))
+               goto nla_put_failure;
+
+       if (nl80211_send_chandef(msg, chandef))
                goto nla_put_failure;
 
        genlmsg_end(msg, hdr);
@@ -8914,46 +9062,96 @@ EXPORT_SYMBOL(cfg80211_probe_status);
 
 void cfg80211_report_obss_beacon(struct wiphy *wiphy,
                                 const u8 *frame, size_t len,
-                                int freq, int sig_dbm, gfp_t gfp)
+                                int freq, int sig_dbm)
 {
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wiphy);
        struct sk_buff *msg;
        void *hdr;
-       u32 nlportid = ACCESS_ONCE(rdev->ap_beacons_nlportid);
+       struct cfg80211_beacon_registration *reg;
 
        trace_cfg80211_report_obss_beacon(wiphy, frame, len, freq, sig_dbm);
 
-       if (!nlportid)
-               return;
+       spin_lock_bh(&rdev->beacon_registrations_lock);
+       list_for_each_entry(reg, &rdev->beacon_registrations, list) {
+               msg = nlmsg_new(len + 100, GFP_ATOMIC);
+               if (!msg) {
+                       spin_unlock_bh(&rdev->beacon_registrations_lock);
+                       return;
+               }
+
+               hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
+               if (!hdr)
+                       goto nla_put_failure;
+
+               if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
+                   (freq &&
+                    nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
+                   (sig_dbm &&
+                    nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
+                   nla_put(msg, NL80211_ATTR_FRAME, len, frame))
+                       goto nla_put_failure;
+
+               genlmsg_end(msg, hdr);
 
-       msg = nlmsg_new(len + 100, gfp);
+               genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, reg->nlportid);
+       }
+       spin_unlock_bh(&rdev->beacon_registrations_lock);
+       return;
+
+ nla_put_failure:
+       spin_unlock_bh(&rdev->beacon_registrations_lock);
+       if (hdr)
+               genlmsg_cancel(msg, hdr);
+       nlmsg_free(msg);
+}
+EXPORT_SYMBOL(cfg80211_report_obss_beacon);
+
+void cfg80211_tdls_oper_request(struct net_device *dev, const u8 *peer,
+                               enum nl80211_tdls_operation oper,
+                               u16 reason_code, gfp_t gfp)
+{
+       struct wireless_dev *wdev = dev->ieee80211_ptr;
+       struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct sk_buff *msg;
+       void *hdr;
+       int err;
+
+       trace_cfg80211_tdls_oper_request(wdev->wiphy, dev, peer, oper,
+                                        reason_code);
+
+       msg = nlmsg_new(NLMSG_DEFAULT_SIZE, gfp);
        if (!msg)
                return;
 
-       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_FRAME);
+       hdr = nl80211hdr_put(msg, 0, 0, 0, NL80211_CMD_TDLS_OPER);
        if (!hdr) {
                nlmsg_free(msg);
                return;
        }
 
        if (nla_put_u32(msg, NL80211_ATTR_WIPHY, rdev->wiphy_idx) ||
-           (freq &&
-            nla_put_u32(msg, NL80211_ATTR_WIPHY_FREQ, freq)) ||
-           (sig_dbm &&
-            nla_put_u32(msg, NL80211_ATTR_RX_SIGNAL_DBM, sig_dbm)) ||
-           nla_put(msg, NL80211_ATTR_FRAME, len, frame))
+           nla_put_u32(msg, NL80211_ATTR_IFINDEX, dev->ifindex) ||
+           nla_put_u8(msg, NL80211_ATTR_TDLS_OPERATION, oper) ||
+           nla_put(msg, NL80211_ATTR_MAC, ETH_ALEN, peer) ||
+           (reason_code > 0 &&
+            nla_put_u16(msg, NL80211_ATTR_REASON_CODE, reason_code)))
                goto nla_put_failure;
 
-       genlmsg_end(msg, hdr);
+       err = genlmsg_end(msg, hdr);
+       if (err < 0) {
+               nlmsg_free(msg);
+               return;
+       }
 
-       genlmsg_unicast(wiphy_net(&rdev->wiphy), msg, nlportid);
+       genlmsg_multicast_netns(wiphy_net(&rdev->wiphy), msg, 0,
+                               nl80211_mlme_mcgrp.id, gfp);
        return;
 
  nla_put_failure:
        genlmsg_cancel(msg, hdr);
        nlmsg_free(msg);
 }
-EXPORT_SYMBOL(cfg80211_report_obss_beacon);
+EXPORT_SYMBOL(cfg80211_tdls_oper_request);
 
 static int nl80211_netlink_notify(struct notifier_block * nb,
                                  unsigned long state,
@@ -8962,6 +9160,7 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
        struct netlink_notify *notify = _notify;
        struct cfg80211_registered_device *rdev;
        struct wireless_dev *wdev;
+       struct cfg80211_beacon_registration *reg, *tmp;
 
        if (state != NETLINK_URELEASE)
                return NOTIFY_DONE;
@@ -8971,8 +9170,17 @@ static int nl80211_netlink_notify(struct notifier_block * nb,
        list_for_each_entry_rcu(rdev, &cfg80211_rdev_list, list) {
                list_for_each_entry_rcu(wdev, &rdev->wdev_list, list)
                        cfg80211_mlme_unregister_socket(wdev, notify->portid);
-               if (rdev->ap_beacons_nlportid == notify->portid)
-                       rdev->ap_beacons_nlportid = 0;
+
+               spin_lock_bh(&rdev->beacon_registrations_lock);
+               list_for_each_entry_safe(reg, tmp, &rdev->beacon_registrations,
+                                        list) {
+                       if (reg->nlportid == notify->portid) {
+                               list_del(&reg->list);
+                               kfree(reg);
+                               break;
+                       }
+               }
+               spin_unlock_bh(&rdev->beacon_registrations_lock);
        }
 
        rcu_read_unlock();
index f6153516068c30dce59e4283d9abfc0591adebfb..2acba8477e9db41a196e7b2a83aaff057d3babb8 100644 (file)
@@ -76,13 +76,11 @@ void nl80211_send_ibss_bssid(struct cfg80211_registered_device *rdev,
 void nl80211_send_remain_on_channel(struct cfg80211_registered_device *rdev,
                                    struct wireless_dev *wdev, u64 cookie,
                                    struct ieee80211_channel *chan,
-                                   enum nl80211_channel_type channel_type,
                                    unsigned int duration, gfp_t gfp);
 void nl80211_send_remain_on_channel_cancel(
        struct cfg80211_registered_device *rdev,
        struct wireless_dev *wdev,
-       u64 cookie, struct ieee80211_channel *chan,
-       enum nl80211_channel_type channel_type, gfp_t gfp);
+       u64 cookie, struct ieee80211_channel *chan, gfp_t gfp);
 
 void nl80211_send_sta_event(struct cfg80211_registered_device *rdev,
                            struct net_device *dev, const u8 *mac_addr,
@@ -129,8 +127,8 @@ void nl80211_pmksa_candidate_notify(struct cfg80211_registered_device *rdev,
                                    const u8 *bssid, bool preauth, gfp_t gfp);
 
 void nl80211_ch_switch_notify(struct cfg80211_registered_device *rdev,
-                             struct net_device *dev, int freq,
-                             enum nl80211_channel_type type, gfp_t gfp);
+                             struct net_device *dev,
+                             struct cfg80211_chan_def *chandef, gfp_t gfp);
 
 bool nl80211_unexpected_frame(struct net_device *dev,
                              const u8 *addr, gfp_t gfp);
index eb5f8974e1481c92f064f320de77569917a21bd0..6c0c8191f83771e361fd1f4a14424383d347d7f6 100644 (file)
@@ -359,12 +359,11 @@ rdev_libertas_set_mesh_channel(struct cfg80211_registered_device *rdev,
 
 static inline int
 rdev_set_monitor_channel(struct cfg80211_registered_device *rdev,
-                        struct ieee80211_channel *chan,
-                        enum nl80211_channel_type channel_type)
+                        struct cfg80211_chan_def *chandef)
 {
        int ret;
-       trace_rdev_set_monitor_channel(&rdev->wiphy, chan, channel_type);
-       ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chan, channel_type);
+       trace_rdev_set_monitor_channel(&rdev->wiphy, chandef);
+       ret = rdev->ops->set_monitor_channel(&rdev->wiphy, chandef);
        trace_rdev_return_int(&rdev->wiphy, ret);
        return ret;
 }
@@ -476,21 +475,22 @@ rdev_set_wiphy_params(struct cfg80211_registered_device *rdev, u32 changed)
 }
 
 static inline int rdev_set_tx_power(struct cfg80211_registered_device *rdev,
+                                   struct wireless_dev *wdev,
                                    enum nl80211_tx_power_setting type, int mbm)
 {
        int ret;
-       trace_rdev_set_tx_power(&rdev->wiphy, type, mbm);
-       ret = rdev->ops->set_tx_power(&rdev->wiphy, type, mbm);
+       trace_rdev_set_tx_power(&rdev->wiphy, wdev, type, mbm);
+       ret = rdev->ops->set_tx_power(&rdev->wiphy, wdev, type, mbm);
        trace_rdev_return_int(&rdev->wiphy, ret);
        return ret;
 }
 
 static inline int rdev_get_tx_power(struct cfg80211_registered_device *rdev,
-                                   int *dbm)
+                                   struct wireless_dev *wdev, int *dbm)
 {
        int ret;
-       trace_rdev_get_tx_power(&rdev->wiphy);
-       ret = rdev->ops->get_tx_power(&rdev->wiphy, dbm);
+       trace_rdev_get_tx_power(&rdev->wiphy, wdev);
+       ret = rdev->ops->get_tx_power(&rdev->wiphy, wdev, dbm);
        trace_rdev_return_int_int(&rdev->wiphy, ret, *dbm);
        return ret;
 }
@@ -599,14 +599,12 @@ static inline int
 rdev_remain_on_channel(struct cfg80211_registered_device *rdev,
                       struct wireless_dev *wdev,
                       struct ieee80211_channel *chan,
-                      enum nl80211_channel_type channel_type,
                       unsigned int duration, u64 *cookie)
 {
        int ret;
-       trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, channel_type,
-                                    duration);
+       trace_rdev_remain_on_channel(&rdev->wiphy, wdev, chan, duration);
        ret = rdev->ops->remain_on_channel(&rdev->wiphy, wdev, chan,
-                                           channel_type, duration, cookie);
+                                          duration, cookie);
        trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
        return ret;
 }
@@ -625,17 +623,15 @@ rdev_cancel_remain_on_channel(struct cfg80211_registered_device *rdev,
 static inline int rdev_mgmt_tx(struct cfg80211_registered_device *rdev,
                               struct wireless_dev *wdev,
                               struct ieee80211_channel *chan, bool offchan,
-                              enum nl80211_channel_type channel_type,
-                              bool channel_type_valid, unsigned int wait,
-                              const u8 *buf, size_t len, bool no_cck,
-                              bool dont_wait_for_ack, u64 *cookie)
+                              unsigned int wait, const u8 *buf, size_t len,
+                              bool no_cck, bool dont_wait_for_ack, u64 *cookie)
 {
        int ret;
-       trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan, channel_type,
-                          channel_type_valid, wait, no_cck, dont_wait_for_ack);
+       trace_rdev_mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
+                          wait, no_cck, dont_wait_for_ack);
        ret = rdev->ops->mgmt_tx(&rdev->wiphy, wdev, chan, offchan,
-                                 channel_type, channel_type_valid, wait, buf,
-                                 len, no_cck, dont_wait_for_ack, cookie);
+                                 wait, buf, len, no_cck,
+                                 dont_wait_for_ack, cookie);
        trace_rdev_return_int_cookie(&rdev->wiphy, ret, *cookie);
        return ret;
 }
@@ -847,14 +843,17 @@ static inline void rdev_get_et_strings(struct cfg80211_registered_device *rdev,
        trace_rdev_return_void(&rdev->wiphy);
 }
 
-static inline struct ieee80211_channel
-*rdev_get_channel(struct cfg80211_registered_device *rdev,
-                 struct wireless_dev *wdev, enum nl80211_channel_type *type)
+static inline int
+rdev_get_channel(struct cfg80211_registered_device *rdev,
+                struct wireless_dev *wdev,
+                struct cfg80211_chan_def *chandef)
 {
-       struct ieee80211_channel *ret;
+       int ret;
+
        trace_rdev_get_channel(&rdev->wiphy, wdev);
-       ret = rdev->ops->get_channel(&rdev->wiphy, wdev, type);
-       trace_rdev_return_channel(&rdev->wiphy, ret, *type);
+       ret = rdev->ops->get_channel(&rdev->wiphy, wdev, chandef);
+       trace_rdev_return_chandef(&rdev->wiphy, ret, chandef);
+
        return ret;
 }
 
index 7f97a087f452d7c8262592e8403a1b2433ee0e25..9596015975d24b011cc22056ed3470bf3c25aabf 100644 (file)
@@ -771,6 +771,38 @@ cfg80211_bss_update(struct cfg80211_registered_device *dev,
        return found;
 }
 
+static struct ieee80211_channel *
+cfg80211_get_bss_channel(struct wiphy *wiphy, const u8 *ie, size_t ielen,
+                        struct ieee80211_channel *channel)
+{
+       const u8 *tmp;
+       u32 freq;
+       int channel_number = -1;
+
+       tmp = cfg80211_find_ie(WLAN_EID_DS_PARAMS, ie, ielen);
+       if (tmp && tmp[1] == 1) {
+               channel_number = tmp[2];
+       } else {
+               tmp = cfg80211_find_ie(WLAN_EID_HT_OPERATION, ie, ielen);
+               if (tmp && tmp[1] >= sizeof(struct ieee80211_ht_operation)) {
+                       struct ieee80211_ht_operation *htop = (void *)(tmp + 2);
+
+                       channel_number = htop->primary_chan;
+               }
+       }
+
+       if (channel_number < 0)
+               return channel;
+
+       freq = ieee80211_channel_to_frequency(channel_number, channel->band);
+       channel = ieee80211_get_channel(wiphy, freq);
+       if (!channel)
+               return NULL;
+       if (channel->flags & IEEE80211_CHAN_DISABLED)
+               return NULL;
+       return channel;
+}
+
 struct cfg80211_bss*
 cfg80211_inform_bss(struct wiphy *wiphy,
                    struct ieee80211_channel *channel,
@@ -790,6 +822,10 @@ cfg80211_inform_bss(struct wiphy *wiphy,
                        (signal < 0 || signal > 100)))
                return NULL;
 
+       channel = cfg80211_get_bss_channel(wiphy, ie, ielen, channel);
+       if (!channel)
+               return NULL;
+
        res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
        if (!res)
                return NULL;
@@ -839,11 +875,13 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
                          s32 signal, gfp_t gfp)
 {
        struct cfg80211_internal_bss *res;
-
        size_t ielen = len - offsetof(struct ieee80211_mgmt,
                                      u.probe_resp.variable);
        size_t privsz;
 
+       BUILD_BUG_ON(offsetof(struct ieee80211_mgmt, u.probe_resp.variable) !=
+                       offsetof(struct ieee80211_mgmt, u.beacon.variable));
+
        trace_cfg80211_inform_bss_frame(wiphy, channel, mgmt, len, signal);
 
        if (WARN_ON(!mgmt))
@@ -861,6 +899,11 @@ cfg80211_inform_bss_frame(struct wiphy *wiphy,
 
        privsz = wiphy->bss_priv_size;
 
+       channel = cfg80211_get_bss_channel(wiphy, mgmt->u.beacon.variable,
+                                          ielen, channel);
+       if (!channel)
+               return NULL;
+
        res = kzalloc(sizeof(*res) + privsz + ielen, gfp);
        if (!res)
                return NULL;
index 0ca71caf85fbbaedd1e7d2e28225aa2798dd8c38..2134576f426e0f5853255b3d76fb2e3bff5fe24c 100644 (file)
 #define MAC_PR_FMT "%pM"
 #define MAC_PR_ARG(entry_mac) (__entry->entry_mac)
 
-#define WIPHY_ENTRY MAC_ENTRY(wiphy_mac)
-#define WIPHY_ASSIGN MAC_ASSIGN(wiphy_mac, wiphy->perm_addr)
-#define WIPHY_PR_FMT "wiphy " MAC_PR_FMT
-#define WIPHY_PR_ARG MAC_PR_ARG(wiphy_mac)
-
-#define WDEV_ENTRY __field(u32, id)
-#define WDEV_ASSIGN (__entry->id) = (wdev->identifier)
-#define WDEV_PR_FMT ", wdev id: %u"
-#define WDEV_PR_ARG (__entry->id)
-
-#define NETDEV_ENTRY __array(char, name, IFNAMSIZ) \
-                    MAC_ENTRY(netdev_addr)        \
-                    __field(int, ifindex)
+#define MAXNAME                32
+#define WIPHY_ENTRY    __array(char, wiphy_name, 32)
+#define WIPHY_ASSIGN   strlcpy(__entry->wiphy_name, wiphy_name(wiphy), MAXNAME)
+#define WIPHY_PR_FMT   "%s"
+#define WIPHY_PR_ARG   __entry->wiphy_name
+
+#define WDEV_ENTRY     __field(u32, id)
+#define WDEV_ASSIGN    (__entry->id) = (wdev ? wdev->identifier : 0)
+#define WDEV_PR_FMT    "wdev(%u)"
+#define WDEV_PR_ARG    (__entry->id)
+
+#define NETDEV_ENTRY   __array(char, name, IFNAMSIZ) \
+                       __field(int, ifindex)
 #define NETDEV_ASSIGN                                         \
        do {                                                   \
                memcpy(__entry->name, netdev->name, IFNAMSIZ); \
-               MAC_ASSIGN(netdev_addr, netdev->dev_addr);     \
                (__entry->ifindex) = (netdev->ifindex);        \
        } while (0)
-#define NETDEV_PR_FMT ", netdev - name: %s, addr: " MAC_PR_FMT \
-                     ", intf index: %d"
-#define NETDEV_PR_ARG (__entry->name), MAC_PR_ARG(netdev_addr), \
-                     (__entry->ifindex)
+#define NETDEV_PR_FMT  "netdev:%s(%d)"
+#define NETDEV_PR_ARG  __entry->name, __entry->ifindex
 
 #define MESH_CFG_ENTRY __field(u16, dot11MeshRetryTimeout)                \
                       __field(u16, dot11MeshConfirmTimeout)               \
                        __entry->center_freq = 0;                 \
                }                                                 \
        } while (0)
-#define CHAN_PR_FMT "band: %d, freq: %u"
+#define CHAN_PR_FMT "band: %d, freq: %u"
 #define CHAN_PR_ARG __entry->band, __entry->center_freq
 
+#define CHAN_DEF_ENTRY __field(enum ieee80211_band, band)              \
+                      __field(u32, control_freq)                       \
+                      __field(u32, width)                              \
+                      __field(u32, center_freq1)                       \
+                      __field(u32, center_freq2)
+#define CHAN_DEF_ASSIGN(chandef)                                       \
+       do {                                                            \
+               if ((chandef) && (chandef)->chan) {                     \
+                       __entry->band = (chandef)->chan->band;          \
+                       __entry->control_freq =                         \
+                               (chandef)->chan->center_freq;           \
+                       __entry->width = (chandef)->width;              \
+                       __entry->center_freq1 = (chandef)->center_freq1;\
+                       __entry->center_freq2 = (chandef)->center_freq2;\
+               } else {                                                \
+                       __entry->band = 0;                              \
+                       __entry->control_freq = 0;                      \
+                       __entry->width = 0;                             \
+                       __entry->center_freq1 = 0;                      \
+                       __entry->center_freq2 = 0;                      \
+               }                                                       \
+       } while (0)
+#define CHAN_DEF_PR_FMT                                                        \
+       "band: %d, control freq: %u, width: %d, cf1: %u, cf2: %u"
+#define CHAN_DEF_PR_ARG __entry->band, __entry->control_freq,          \
+                       __entry->width, __entry->center_freq1,          \
+                       __entry->center_freq2
+
 #define SINFO_ENTRY __field(int, generation)       \
                    __field(u32, connected_time)    \
                    __field(u32, inactive_time)     \
@@ -260,11 +285,6 @@ DEFINE_EVENT(wiphy_only_evt, rdev_get_antenna,
        TP_ARGS(wiphy)
 );
 
-DEFINE_EVENT(wiphy_only_evt, rdev_get_tx_power,
-       TP_PROTO(struct wiphy *wiphy),
-       TP_ARGS(wiphy)
-);
-
 DEFINE_EVENT(wiphy_only_evt, rdev_rfkill_poll,
        TP_PROTO(struct wiphy *wiphy),
        TP_ARGS(wiphy)
@@ -318,7 +338,7 @@ DECLARE_EVENT_CLASS(wiphy_wdev_evt,
                WIPHY_ASSIGN;
                WDEV_ASSIGN;
        ),
-       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT, WIPHY_PR_ARG, WDEV_PR_ARG)
 );
 
 DEFINE_EVENT(wiphy_wdev_evt, rdev_return_wdev,
@@ -345,7 +365,7 @@ TRACE_EVENT(rdev_change_virtual_intf,
                NETDEV_ASSIGN;
                __entry->type = type;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", type: %d",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", type: %d",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->type)
 );
 
@@ -367,7 +387,7 @@ DECLARE_EVENT_CLASS(key_handle,
                __entry->key_index = key_index;
                __entry->pairwise = pairwise;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key_index: %u, pairwise: %s, mac addr: " MAC_PR_FMT,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key_index: %u, pairwise: %s, mac addr: " MAC_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index,
                  BOOL_TO_STR(__entry->pairwise), MAC_PR_ARG(mac_addr))
 );
@@ -408,7 +428,7 @@ TRACE_EVENT(rdev_set_default_key,
                __entry->unicast = unicast;
                __entry->multicast = multicast;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u, unicast: %s, multicast: %s",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key index: %u, unicast: %s, multicast: %s",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index,
                  BOOL_TO_STR(__entry->unicast),
                  BOOL_TO_STR(__entry->multicast))
@@ -427,7 +447,7 @@ TRACE_EVENT(rdev_set_default_mgmt_key,
                NETDEV_ASSIGN;
                __entry->key_index = key_index;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", key index: %u",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", key index: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->key_index)
 );
 
@@ -438,7 +458,7 @@ TRACE_EVENT(rdev_start_ap,
        TP_STRUCT__entry(
                WIPHY_ENTRY
                NETDEV_ENTRY
-               CHAN_ENTRY
+               CHAN_DEF_ENTRY
                __field(int, beacon_interval)
                __field(int, dtim_period)
                __array(char, ssid, IEEE80211_MAX_SSID_LEN + 1)
@@ -451,7 +471,7 @@ TRACE_EVENT(rdev_start_ap,
        TP_fast_assign(
                WIPHY_ASSIGN;
                NETDEV_ASSIGN;
-               CHAN_ASSIGN(settings->channel);
+               CHAN_DEF_ASSIGN(&settings->chandef);
                __entry->beacon_interval = settings->beacon_interval;
                __entry->dtim_period = settings->dtim_period;
                __entry->hidden_ssid = settings->hidden_ssid;
@@ -462,11 +482,11 @@ TRACE_EVENT(rdev_start_ap,
                memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
                memcpy(__entry->ssid, settings->ssid, settings->ssid_len);
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", AP settings - ssid: %s, "
-                 CHAN_PR_FMT ", beacon interval: %d, dtim period: %d, "
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", AP settings - ssid: %s, "
+                 CHAN_DEF_PR_FMT ", beacon interval: %d, dtim period: %d, "
                  "hidden ssid: %d, wpa versions: %u, privacy: %s, "
                  "auth type: %d, inactivity timeout: %d",
-                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_PR_ARG,
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ssid, CHAN_DEF_PR_ARG,
                  __entry->beacon_interval, __entry->dtim_period,
                  __entry->hidden_ssid, __entry->wpa_ver,
                  BOOL_TO_STR(__entry->privacy), __entry->auth_type,
@@ -515,7 +535,7 @@ TRACE_EVENT(rdev_change_beacon,
                                       info->probe_resp, info->probe_resp_len);
                }
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG)
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG)
 );
 
 DECLARE_EVENT_CLASS(wiphy_netdev_evt,
@@ -529,7 +549,7 @@ DECLARE_EVENT_CLASS(wiphy_netdev_evt,
                WIPHY_ASSIGN;
                NETDEV_ASSIGN;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG)
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT, WIPHY_PR_ARG, NETDEV_PR_ARG)
 );
 
 DEFINE_EVENT(wiphy_netdev_evt, rdev_stop_ap,
@@ -607,7 +627,7 @@ DECLARE_EVENT_CLASS(station_add_change,
                        memcpy(__entry->ht_capa, params->ht_capa,
                               sizeof(struct ieee80211_ht_cap));
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT
                  ", station flags mask: %u, station flags set: %u, "
                  "station modify mask: %u, listen interval: %d, aid: %u, "
                  "plink action: %u, plink state: %u, uapsd queues: %u",
@@ -643,7 +663,7 @@ DECLARE_EVENT_CLASS(wiphy_netdev_mac_evt,
                NETDEV_ASSIGN;
                MAC_ASSIGN(sta_mac, mac);
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mac: " MAC_PR_FMT,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", mac: " MAC_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac))
 );
 
@@ -683,7 +703,7 @@ TRACE_EVENT(rdev_dump_station,
                MAC_ASSIGN(sta_mac, mac);
                __entry->idx = idx;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", station mac: " MAC_PR_FMT ", idx: %d",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(sta_mac),
                  __entry->idx)
 );
@@ -721,7 +741,7 @@ DECLARE_EVENT_CLASS(mpath_evt,
                MAC_ASSIGN(dst, dst);
                MAC_ASSIGN(next_hop, next_hop);
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", destination: " MAC_PR_FMT ", next hop: " MAC_PR_FMT,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", destination: " MAC_PR_FMT ", next hop: " MAC_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(dst),
                  MAC_PR_ARG(next_hop))
 );
@@ -762,7 +782,7 @@ TRACE_EVENT(rdev_dump_mpath,
                MAC_ASSIGN(next_hop, next_hop);
                __entry->idx = idx;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d, destination: "
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d, destination: "
                  MAC_PR_FMT ", next hop: " MAC_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx, MAC_PR_ARG(dst),
                  MAC_PR_ARG(next_hop))
@@ -839,7 +859,7 @@ TRACE_EVENT(rdev_update_mesh_config,
                MESH_CFG_ASSIGN;
                __entry->mask = mask;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", mask: %u",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", mask: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->mask)
 );
 
@@ -858,7 +878,7 @@ TRACE_EVENT(rdev_join_mesh,
                NETDEV_ASSIGN;
                MESH_CFG_ASSIGN;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG)
 );
 
@@ -884,7 +904,7 @@ TRACE_EVENT(rdev_change_bss,
                __entry->ap_isolate = params->ap_isolate;
                __entry->ht_opmode = params->ht_opmode;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", use cts prot: %d, "
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", use cts prot: %d, "
                  "use short preamble: %d, use short slot time: %d, "
                  "ap isolate: %d, ht opmode: %d",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->use_cts_prot,
@@ -914,7 +934,7 @@ TRACE_EVENT(rdev_set_txq_params,
                __entry->cwmax = params->cwmax;
                __entry->aifs = params->aifs;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", ac: %d, txop: %u, cwmin: %u, cwmax: %u, aifs: %u",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", ac: %d, txop: %u, cwmin: %u, cwmax: %u, aifs: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->ac, __entry->txop,
                  __entry->cwmin, __entry->cwmax, __entry->aifs)
 );
@@ -933,26 +953,24 @@ TRACE_EVENT(rdev_libertas_set_mesh_channel,
                NETDEV_ASSIGN;
                CHAN_ASSIGN(chan);
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT CHAN_PR_FMT, WIPHY_PR_ARG,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " CHAN_PR_FMT, WIPHY_PR_ARG,
                  NETDEV_PR_ARG, CHAN_PR_ARG)
 );
 
 TRACE_EVENT(rdev_set_monitor_channel,
-       TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan,
-                enum nl80211_channel_type chan_type),
-       TP_ARGS(wiphy, chan, chan_type),
+       TP_PROTO(struct wiphy *wiphy,
+                struct cfg80211_chan_def *chandef),
+       TP_ARGS(wiphy, chandef),
        TP_STRUCT__entry(
                WIPHY_ENTRY
-               CHAN_ENTRY
-               __field(enum nl80211_channel_type, chan_type)
+               CHAN_DEF_ENTRY
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
-               CHAN_ASSIGN(chan);
-               __entry->chan_type = chan_type;
+               CHAN_DEF_ASSIGN(chandef);
        ),
-       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type : %d",
-                 WIPHY_PR_ARG, CHAN_PR_ARG, __entry->chan_type)
+       TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
+                 WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
 );
 
 TRACE_EVENT(rdev_auth,
@@ -974,7 +992,7 @@ TRACE_EVENT(rdev_auth,
                        memset(__entry->bssid, 0, ETH_ALEN);
                __entry->auth_type = req->auth_type;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", auth type: %d, bssid: " MAC_PR_FMT,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", auth type: %d, bssid: " MAC_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->auth_type,
                  MAC_PR_ARG(bssid))
 );
@@ -1002,7 +1020,7 @@ TRACE_EVENT(rdev_assoc,
                __entry->use_mfp = req->use_mfp;
                __entry->flags = req->flags;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
                  ", previous bssid: " MAC_PR_FMT ", use mfp: %s, flags: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid),
                  MAC_PR_ARG(prev_bssid), BOOL_TO_STR(__entry->use_mfp),
@@ -1025,7 +1043,7 @@ TRACE_EVENT(rdev_deauth,
                MAC_ASSIGN(bssid, req->bssid);
                __entry->reason_code = req->reason_code;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", reason: %u",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", reason: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid),
                  __entry->reason_code)
 );
@@ -1051,7 +1069,7 @@ TRACE_EVENT(rdev_disassoc,
                __entry->reason_code = req->reason_code;
                __entry->local_state_change = req->local_state_change;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
                  ", reason: %u, local state change: %s",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid),
                  __entry->reason_code,
@@ -1072,7 +1090,7 @@ TRACE_EVENT(rdev_mgmt_tx_cancel_wait,
                WDEV_ASSIGN;
                __entry->cookie = cookie;
        ),
-       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu ",
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie: %llu ",
                  WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie)
 );
 
@@ -1092,7 +1110,7 @@ TRACE_EVENT(rdev_set_power_mgmt,
                __entry->enabled = enabled;
                __entry->timeout = timeout;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", %senabled, timeout: %d ",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", %senabled, timeout: %d ",
                  WIPHY_PR_ARG, NETDEV_PR_ARG,
                  __entry->enabled ? "" : "not ", __entry->timeout)
 );
@@ -1122,7 +1140,7 @@ TRACE_EVENT(rdev_connect,
                __entry->wpa_versions = sme->crypto.wpa_versions;
                __entry->flags = sme->flags;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT
                  ", ssid: %s, auth type: %d, privacy: %s, wpa versions: %u, "
                  "flags: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid,
@@ -1147,7 +1165,7 @@ TRACE_EVENT(rdev_set_cqm_rssi_config,
                __entry->rssi_thold = rssi_thold;
                __entry->rssi_hyst = rssi_hyst;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT
                  ", rssi_thold: %d, rssi_hyst: %u ",
                  WIPHY_PR_ARG, NETDEV_PR_ARG,
                 __entry->rssi_thold, __entry->rssi_hyst)
@@ -1171,7 +1189,7 @@ TRACE_EVENT(rdev_set_cqm_txe_config,
                __entry->pkts = pkts;
                __entry->intvl = intvl;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", rate: %u, packets: %u, interval: %u",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", rate: %u, packets: %u, interval: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->rate, __entry->pkts,
                  __entry->intvl)
 );
@@ -1190,7 +1208,7 @@ TRACE_EVENT(rdev_disconnect,
                NETDEV_ASSIGN;
                __entry->reason_code = reason_code;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", reason code: %u", WIPHY_PR_ARG,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", reason code: %u", WIPHY_PR_ARG,
                  NETDEV_PR_ARG, __entry->reason_code)
 );
 
@@ -1211,7 +1229,7 @@ TRACE_EVENT(rdev_join_ibss,
                memset(__entry->ssid, 0, IEEE80211_MAX_SSID_LEN + 1);
                memcpy(__entry->ssid, params->ssid, params->ssid_len);
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", ssid: %s",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT ", ssid: %s",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid), __entry->ssid)
 );
 
@@ -1230,22 +1248,29 @@ TRACE_EVENT(rdev_set_wiphy_params,
                  WIPHY_PR_ARG, __entry->changed)
 );
 
+DEFINE_EVENT(wiphy_wdev_evt, rdev_get_tx_power,
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev),
+       TP_ARGS(wiphy, wdev)
+);
+
 TRACE_EVENT(rdev_set_tx_power,
-       TP_PROTO(struct wiphy *wiphy, enum nl80211_tx_power_setting type,
-                int mbm),
-       TP_ARGS(wiphy, type, mbm),
+       TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
+                enum nl80211_tx_power_setting type, int mbm),
+       TP_ARGS(wiphy, wdev, type, mbm),
        TP_STRUCT__entry(
                WIPHY_ENTRY
+               WDEV_ENTRY
                __field(enum nl80211_tx_power_setting, type)
                __field(int, mbm)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
+               WDEV_ASSIGN;
                __entry->type = type;
                __entry->mbm = mbm;
        ),
-       TP_printk(WIPHY_PR_FMT ", type: %d, mbm: %d",
-                 WIPHY_PR_ARG, __entry->type, __entry->mbm)
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", type: %u, mbm: %d",
+                 WIPHY_PR_ARG, WDEV_PR_ARG,__entry->type, __entry->mbm)
 );
 
 TRACE_EVENT(rdev_return_int_int,
@@ -1305,7 +1330,7 @@ TRACE_EVENT(rdev_set_bitrate_mask,
                NETDEV_ASSIGN;
                MAC_ASSIGN(peer, peer);
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", peer: " MAC_PR_FMT,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
 );
 
@@ -1325,7 +1350,7 @@ TRACE_EVENT(rdev_mgmt_frame_register,
                __entry->frame_type = frame_type;
                __entry->reg = reg;
        ),
-       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", frame_type: %u, reg: %s ",
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", frame_type: 0x%.2x, reg: %s ",
                  WIPHY_PR_ARG, WDEV_PR_ARG, __entry->frame_type,
                  __entry->reg ? "true" : "false")
 );
@@ -1411,7 +1436,7 @@ TRACE_EVENT(rdev_sched_scan_start,
                WIPHY_ASSIGN;
                NETDEV_ASSIGN;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG)
 );
 
@@ -1439,7 +1464,7 @@ TRACE_EVENT(rdev_tdls_mgmt,
                __entry->status_code = status_code;
                memcpy(__get_dynamic_array(buf), buf, len);
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", action_code: %u, "
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", action_code: %u, "
                  "dialog_token: %u, status_code: %u, buf: %#.2x ",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer),
                  __entry->action_code, __entry->dialog_token,
@@ -1459,7 +1484,7 @@ TRACE_EVENT(rdev_dump_survey,
                NETDEV_ASSIGN;
                __entry->idx = idx;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", index: %d",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", index: %d",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->idx)
 );
 
@@ -1516,7 +1541,7 @@ TRACE_EVENT(rdev_tdls_oper,
                MAC_ASSIGN(peer, peer);
                __entry->oper = oper;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT ", oper: %d",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT ", oper: %d",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->oper)
 );
 
@@ -1534,7 +1559,7 @@ DECLARE_EVENT_CLASS(rdev_pmksa,
                NETDEV_ASSIGN;
                MAC_ASSIGN(bssid, pmksa->bssid);
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", bssid: " MAC_PR_FMT,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", bssid: " MAC_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(bssid))
 );
 
@@ -1552,7 +1577,7 @@ TRACE_EVENT(rdev_probe_client,
                NETDEV_ASSIGN;
                MAC_ASSIGN(peer, peer);
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT MAC_PR_FMT,
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", " MAC_PR_FMT,
                  WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer))
 );
 
@@ -1571,25 +1596,22 @@ DEFINE_EVENT(rdev_pmksa, rdev_del_pmksa,
 TRACE_EVENT(rdev_remain_on_channel,
        TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
                 struct ieee80211_channel *chan,
-                enum nl80211_channel_type channel_type, unsigned int duration),
-       TP_ARGS(wiphy, wdev, chan, channel_type, duration),
+                unsigned int duration),
+       TP_ARGS(wiphy, wdev, chan, duration),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                WDEV_ENTRY
                CHAN_ENTRY
-               __field(enum nl80211_channel_type, channel_type)
                __field(unsigned int, duration)
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
                WDEV_ASSIGN;
                CHAN_ASSIGN(chan);
-               __entry->channel_type = channel_type;
                __entry->duration = duration;
        ),
-       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", channel type: %d, duration: %u",
-                 WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->channel_type,
-                 __entry->duration)
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", duration: %u",
+                 WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG, __entry->duration)
 );
 
 TRACE_EVENT(rdev_return_int_cookie,
@@ -1622,25 +1644,20 @@ TRACE_EVENT(rdev_cancel_remain_on_channel,
                WDEV_ASSIGN;
                __entry->cookie = cookie;
        ),
-       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT ", cookie: %llu",
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", cookie: %llu",
                  WIPHY_PR_ARG, WDEV_PR_ARG, __entry->cookie)
 );
 
 TRACE_EVENT(rdev_mgmt_tx,
        TP_PROTO(struct wiphy *wiphy, struct wireless_dev *wdev,
                 struct ieee80211_channel *chan, bool offchan,
-                enum nl80211_channel_type channel_type,
-                bool channel_type_valid, unsigned int wait, bool no_cck,
-                bool dont_wait_for_ack),
-       TP_ARGS(wiphy, wdev, chan, offchan, channel_type, channel_type_valid,
-               wait, no_cck, dont_wait_for_ack),
+                unsigned int wait, bool no_cck, bool dont_wait_for_ack),
+       TP_ARGS(wiphy, wdev, chan, offchan, wait, no_cck, dont_wait_for_ack),
        TP_STRUCT__entry(
                WIPHY_ENTRY
                WDEV_ENTRY
                CHAN_ENTRY
                __field(bool, offchan)
-               __field(enum nl80211_channel_type, channel_type)
-               __field(bool, channel_type_valid)
                __field(unsigned int, wait)
                __field(bool, no_cck)
                __field(bool, dont_wait_for_ack)
@@ -1650,18 +1667,14 @@ TRACE_EVENT(rdev_mgmt_tx,
                WDEV_ASSIGN;
                CHAN_ASSIGN(chan);
                __entry->offchan = offchan;
-               __entry->channel_type = channel_type;
-               __entry->channel_type_valid = channel_type_valid;
                __entry->wait = wait;
                __entry->no_cck = no_cck;
                __entry->dont_wait_for_ack = dont_wait_for_ack;
        ),
-       TP_printk(WIPHY_PR_FMT WDEV_PR_FMT CHAN_PR_FMT ", offchan: %s, "
-                 "channel type: %d, channel type valid: %s, wait: %u, "
-                 "no cck: %s, dont wait for ack: %s",
+       TP_printk(WIPHY_PR_FMT ", " WDEV_PR_FMT ", " CHAN_PR_FMT ", offchan: %s,"
+                 " wait: %u, no cck: %s, dont wait for ack: %s",
                  WIPHY_PR_ARG, WDEV_PR_ARG, CHAN_PR_ARG,
-                 BOOL_TO_STR(__entry->offchan), __entry->channel_type,
-                 BOOL_TO_STR(__entry->channel_type_valid), __entry->wait,
+                 BOOL_TO_STR(__entry->offchan), __entry->wait,
                  BOOL_TO_STR(__entry->no_cck),
                  BOOL_TO_STR(__entry->dont_wait_for_ack))
 );
@@ -1680,7 +1693,7 @@ TRACE_EVENT(rdev_set_noack_map,
                NETDEV_ASSIGN;
                __entry->noack_map = noack_map;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", noack_map: %u",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", noack_map: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->noack_map)
 );
 
@@ -1697,7 +1710,7 @@ TRACE_EVENT(rdev_get_et_sset_count,
                NETDEV_ASSIGN;
                __entry->sset = sset;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %d",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %d",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset)
 );
 
@@ -1714,7 +1727,7 @@ TRACE_EVENT(rdev_get_et_strings,
                NETDEV_ASSIGN;
                __entry->sset = sset;
        ),
-       TP_printk(WIPHY_PR_FMT NETDEV_PR_FMT ", sset: %u",
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", sset: %u",
                  WIPHY_PR_ARG, NETDEV_PR_ARG, __entry->sset)
 );
 
@@ -1723,22 +1736,25 @@ DEFINE_EVENT(wiphy_wdev_evt, rdev_get_channel,
        TP_ARGS(wiphy, wdev)
 );
 
-TRACE_EVENT(rdev_return_channel,
-       TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *chan,
-                enum nl80211_channel_type type),
-       TP_ARGS(wiphy, chan, type),
+TRACE_EVENT(rdev_return_chandef,
+       TP_PROTO(struct wiphy *wiphy, int ret,
+                struct cfg80211_chan_def *chandef),
+       TP_ARGS(wiphy, ret, chandef),
        TP_STRUCT__entry(
                WIPHY_ENTRY
-               CHAN_ENTRY
-               __field(enum nl80211_channel_type, type)
+               __field(int, ret)
+               CHAN_DEF_ENTRY
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
-               CHAN_ASSIGN(chan);
-               __entry->type = type;
+               if (ret == 0)
+                       CHAN_DEF_ASSIGN(chandef);
+               else
+                       CHAN_DEF_ASSIGN((struct cfg80211_chan_def *)NULL);
+               __entry->ret = ret;
        ),
-       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel type: %d",
-                 WIPHY_PR_ARG, CHAN_PR_ARG, __entry->type)
+       TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT ", ret: %d",
+                 WIPHY_PR_ARG, CHAN_DEF_PR_ARG, __entry->ret)
 );
 
 DEFINE_EVENT(wiphy_wdev_evt, rdev_start_p2p_device,
@@ -1817,7 +1833,7 @@ TRACE_EVENT(cfg80211_send_rx_assoc,
                MAC_ASSIGN(bssid, bss->bssid);
                CHAN_ASSIGN(bss->channel);
        ),
-       TP_printk(NETDEV_PR_FMT MAC_PR_FMT CHAN_PR_FMT,
+       TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", " CHAN_PR_FMT,
                  NETDEV_PR_ARG, MAC_PR_ARG(bssid), CHAN_PR_ARG)
 );
 
@@ -1884,7 +1900,7 @@ TRACE_EVENT(cfg80211_michael_mic_failure,
                __entry->key_id = key_id;
                memcpy(__entry->tsc, tsc, 6);
        ),
-       TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm",
+       TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT ", key type: %d, key id: %d, tsc: %pm",
                  NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->key_type,
                  __entry->key_id, __entry->tsc)
 );
@@ -1892,47 +1908,41 @@ TRACE_EVENT(cfg80211_michael_mic_failure,
 TRACE_EVENT(cfg80211_ready_on_channel,
        TP_PROTO(struct wireless_dev *wdev, u64 cookie,
                 struct ieee80211_channel *chan,
-                enum nl80211_channel_type channel_type, unsigned int duration),
-       TP_ARGS(wdev, cookie, chan, channel_type, duration),
+                unsigned int duration),
+       TP_ARGS(wdev, cookie, chan, duration),
        TP_STRUCT__entry(
                WDEV_ENTRY
                __field(u64, cookie)
                CHAN_ENTRY
-               __field(enum nl80211_channel_type, channel_type)
                __field(unsigned int, duration)
        ),
        TP_fast_assign(
                WDEV_ASSIGN;
                __entry->cookie = cookie;
                CHAN_ASSIGN(chan);
-               __entry->channel_type = channel_type;
                __entry->duration = duration;
        ),
-       TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d, duration: %u",
+       TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", duration: %u",
                  WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG,
-                 __entry->channel_type, __entry->duration)
+                 __entry->duration)
 );
 
 TRACE_EVENT(cfg80211_ready_on_channel_expired,
        TP_PROTO(struct wireless_dev *wdev, u64 cookie,
-                struct ieee80211_channel *chan,
-                enum nl80211_channel_type channel_type),
-       TP_ARGS(wdev, cookie, chan, channel_type),
+                struct ieee80211_channel *chan),
+       TP_ARGS(wdev, cookie, chan),
        TP_STRUCT__entry(
                WDEV_ENTRY
                __field(u64, cookie)
                CHAN_ENTRY
-               __field(enum nl80211_channel_type, channel_type)
        ),
        TP_fast_assign(
                WDEV_ASSIGN;
                __entry->cookie = cookie;
                CHAN_ASSIGN(chan);
-               __entry->channel_type = channel_type;
        ),
-       TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT ", channel type: %d",
-                 WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG,
-                 __entry->channel_type)
+       TP_printk(WDEV_PR_FMT ", cookie: %llu, " CHAN_PR_FMT,
+                 WDEV_PR_ARG, __entry->cookie, CHAN_PR_ARG)
 );
 
 TRACE_EVENT(cfg80211_new_sta,
@@ -1949,7 +1959,7 @@ TRACE_EVENT(cfg80211_new_sta,
                MAC_ASSIGN(mac_addr, mac_addr);
                SINFO_ASSIGN;
        ),
-       TP_printk(NETDEV_PR_FMT MAC_PR_FMT,
+       TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT,
                  NETDEV_PR_ARG, MAC_PR_ARG(mac_addr))
 );
 
@@ -2008,40 +2018,35 @@ TRACE_EVENT(cfg80211_cqm_rssi_notify,
                  NETDEV_PR_ARG, __entry->rssi_event)
 );
 
-TRACE_EVENT(cfg80211_can_beacon_sec_chan,
-       TP_PROTO(struct wiphy *wiphy, struct ieee80211_channel *channel,
-                enum nl80211_channel_type channel_type),
-       TP_ARGS(wiphy, channel, channel_type),
+TRACE_EVENT(cfg80211_reg_can_beacon,
+       TP_PROTO(struct wiphy *wiphy, struct cfg80211_chan_def *chandef),
+       TP_ARGS(wiphy, chandef),
        TP_STRUCT__entry(
                WIPHY_ENTRY
-               CHAN_ENTRY
-               __field(enum nl80211_channel_type, channel_type)
+               CHAN_DEF_ENTRY
        ),
        TP_fast_assign(
                WIPHY_ASSIGN;
-               CHAN_ASSIGN(channel);
-               __entry->channel_type = channel_type;
+               CHAN_DEF_ASSIGN(chandef);
        ),
-       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT ", channel_type: %d",
-                 WIPHY_PR_ARG, CHAN_PR_ARG, __entry->channel_type)
+       TP_printk(WIPHY_PR_FMT ", " CHAN_DEF_PR_FMT,
+                 WIPHY_PR_ARG, CHAN_DEF_PR_ARG)
 );
 
 TRACE_EVENT(cfg80211_ch_switch_notify,
-       TP_PROTO(struct net_device *netdev, int freq,
-                enum nl80211_channel_type type),
-       TP_ARGS(netdev, freq, type),
+       TP_PROTO(struct net_device *netdev,
+                struct cfg80211_chan_def *chandef),
+       TP_ARGS(netdev, chandef),
        TP_STRUCT__entry(
                NETDEV_ENTRY
-               __field(int, freq)
-               __field(enum nl80211_channel_type, type)
+               CHAN_DEF_ENTRY
        ),
        TP_fast_assign(
                NETDEV_ASSIGN;
-               __entry->freq = freq;
-               __entry->type = type;
+               CHAN_DEF_ASSIGN(chandef);
        ),
-       TP_printk(NETDEV_PR_FMT ", freq: %d, type: %d", NETDEV_PR_ARG,
-                 __entry->freq, __entry->type)
+       TP_printk(NETDEV_PR_FMT ", " CHAN_DEF_PR_FMT,
+                 NETDEV_PR_ARG, CHAN_DEF_PR_ARG)
 );
 
 DECLARE_EVENT_CLASS(cfg80211_rx_evt,
@@ -2055,7 +2060,7 @@ DECLARE_EVENT_CLASS(cfg80211_rx_evt,
                NETDEV_ASSIGN;
                MAC_ASSIGN(addr, addr);
        ),
-       TP_printk(NETDEV_PR_FMT MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr))
+       TP_printk(NETDEV_PR_FMT ", " MAC_PR_FMT, NETDEV_PR_ARG, MAC_PR_ARG(addr))
 );
 
 DEFINE_EVENT(cfg80211_rx_evt, cfg80211_ibss_joined,
@@ -2089,7 +2094,7 @@ TRACE_EVENT(cfg80211_probe_status,
                __entry->cookie = cookie;
                __entry->acked = acked;
        ),
-       TP_printk(NETDEV_PR_FMT MAC_PR_FMT ", cookie: %llu, acked: %s",
+       TP_printk(NETDEV_PR_FMT " addr:" MAC_PR_FMT ", cookie: %llu, acked: %s",
                  NETDEV_PR_ARG, MAC_PR_ARG(addr), __entry->cookie,
                  BOOL_TO_STR(__entry->acked))
 );
@@ -2155,6 +2160,29 @@ TRACE_EVENT(cfg80211_report_obss_beacon,
                  WIPHY_PR_ARG, __entry->freq, __entry->sig_dbm)
 );
 
+TRACE_EVENT(cfg80211_tdls_oper_request,
+       TP_PROTO(struct wiphy *wiphy, struct net_device *netdev, const u8 *peer,
+                enum nl80211_tdls_operation oper, u16 reason_code),
+       TP_ARGS(wiphy, netdev, peer, oper, reason_code),
+       TP_STRUCT__entry(
+               WIPHY_ENTRY
+               NETDEV_ENTRY
+               MAC_ENTRY(peer)
+               __field(enum nl80211_tdls_operation, oper)
+               __field(u16, reason_code)
+       ),
+       TP_fast_assign(
+               WIPHY_ASSIGN;
+               NETDEV_ASSIGN;
+               MAC_ASSIGN(peer, peer);
+               __entry->oper = oper;
+               __entry->reason_code = reason_code;
+       ),
+       TP_printk(WIPHY_PR_FMT ", " NETDEV_PR_FMT ", peer: " MAC_PR_FMT ", oper: %d, reason_code %u",
+                 WIPHY_PR_ARG, NETDEV_PR_ARG, MAC_PR_ARG(peer), __entry->oper,
+                 __entry->reason_code)
+       );
+
 TRACE_EVENT(cfg80211_scan_done,
        TP_PROTO(struct cfg80211_scan_request *request, bool aborted),
        TP_ARGS(request, aborted),
@@ -2216,7 +2244,7 @@ TRACE_EVENT(cfg80211_get_bss,
                __entry->capa_mask = capa_mask;
                __entry->capa_val = capa_val;
        ),
-       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT MAC_PR_FMT ", buf: %#.2x, "
+       TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT ", " MAC_PR_FMT ", buf: %#.2x, "
                  "capa_mask: %d, capa_val: %u", WIPHY_PR_ARG, CHAN_PR_ARG,
                  MAC_PR_ARG(bssid), ((u8 *)__get_dynamic_array(ssid))[0],
                  __entry->capa_mask, __entry->capa_val)
@@ -2240,7 +2268,7 @@ TRACE_EVENT(cfg80211_inform_bss_frame,
                        memcpy(__get_dynamic_array(mgmt), mgmt, len);
                __entry->signal = signal;
        ),
-       TP_printk(WIPHY_PR_FMT CHAN_PR_FMT "signal: %d",
+       TP_printk(WIPHY_PR_FMT ", " CHAN_PR_FMT "signal: %d",
                  WIPHY_PR_ARG, CHAN_PR_ARG, __entry->signal)
 );
 
@@ -2255,7 +2283,7 @@ DECLARE_EVENT_CLASS(cfg80211_bss_evt,
                MAC_ASSIGN(bssid, pub->bssid);
                CHAN_ASSIGN(pub->channel);
        ),
-       TP_printk(MAC_PR_FMT CHAN_PR_FMT, MAC_PR_ARG(bssid), CHAN_PR_ARG)
+       TP_printk(MAC_PR_FMT ", " CHAN_PR_FMT, MAC_PR_ARG(bssid), CHAN_PR_ARG)
 );
 
 DEFINE_EVENT(cfg80211_bss_evt, cfg80211_return_bss,
index 5b6c1df72f3136a79a64621d82890863501eb68b..3cce6e486219d369a2e823ff5f741f24d2d4902e 100644 (file)
@@ -944,14 +944,86 @@ static u32 cfg80211_calculate_bitrate_60g(struct rate_info *rate)
        return __mcs2bitrate[rate->mcs];
 }
 
+static u32 cfg80211_calculate_bitrate_vht(struct rate_info *rate)
+{
+       static const u32 base[4][10] = {
+               {   6500000,
+                  13000000,
+                  19500000,
+                  26000000,
+                  39000000,
+                  52000000,
+                  58500000,
+                  65000000,
+                  78000000,
+                  0,
+               },
+               {  13500000,
+                  27000000,
+                  40500000,
+                  54000000,
+                  81000000,
+                 108000000,
+                 121500000,
+                 135000000,
+                 162000000,
+                 180000000,
+               },
+               {  29300000,
+                  58500000,
+                  87800000,
+                 117000000,
+                 175500000,
+                 234000000,
+                 263300000,
+                 292500000,
+                 351000000,
+                 390000000,
+               },
+               {  58500000,
+                 117000000,
+                 175500000,
+                 234000000,
+                 351000000,
+                 468000000,
+                 526500000,
+                 585000000,
+                 702000000,
+                 780000000,
+               },
+       };
+       u32 bitrate;
+       int idx;
+
+       if (WARN_ON_ONCE(rate->mcs > 9))
+               return 0;
+
+       idx = rate->flags & (RATE_INFO_FLAGS_160_MHZ_WIDTH |
+                            RATE_INFO_FLAGS_80P80_MHZ_WIDTH) ? 3 :
+                 rate->flags & RATE_INFO_FLAGS_80_MHZ_WIDTH ? 2 :
+                 rate->flags & RATE_INFO_FLAGS_40_MHZ_WIDTH ? 1 : 0;
+
+       bitrate = base[idx][rate->mcs];
+       bitrate *= rate->nss;
+
+       if (rate->flags & RATE_INFO_FLAGS_SHORT_GI)
+               bitrate = (bitrate / 9) * 10;
+
+       /* do NOT round down here */
+       return (bitrate + 50000) / 100000;
+}
+
 u32 cfg80211_calculate_bitrate(struct rate_info *rate)
 {
        int modulation, streams, bitrate;
 
-       if (!(rate->flags & RATE_INFO_FLAGS_MCS))
+       if (!(rate->flags & RATE_INFO_FLAGS_MCS) &&
+           !(rate->flags & RATE_INFO_FLAGS_VHT_MCS))
                return rate->legacy;
        if (rate->flags & RATE_INFO_FLAGS_60G)
                return cfg80211_calculate_bitrate_60g(rate);
+       if (rate->flags & RATE_INFO_FLAGS_VHT_MCS)
+               return cfg80211_calculate_bitrate_vht(rate);
 
        /* the formula below does only work for MCS values smaller than 32 */
        if (WARN_ON_ONCE(rate->mcs >= 32))
@@ -980,6 +1052,106 @@ u32 cfg80211_calculate_bitrate(struct rate_info *rate)
 }
 EXPORT_SYMBOL(cfg80211_calculate_bitrate);
 
+int cfg80211_get_p2p_attr(const u8 *ies, unsigned int len,
+                         enum ieee80211_p2p_attr_id attr,
+                         u8 *buf, unsigned int bufsize)
+{
+       u8 *out = buf;
+       u16 attr_remaining = 0;
+       bool desired_attr = false;
+       u16 desired_len = 0;
+
+       while (len > 0) {
+               unsigned int iedatalen;
+               unsigned int copy;
+               const u8 *iedata;
+
+               if (len < 2)
+                       return -EILSEQ;
+               iedatalen = ies[1];
+               if (iedatalen + 2 > len)
+                       return -EILSEQ;
+
+               if (ies[0] != WLAN_EID_VENDOR_SPECIFIC)
+                       goto cont;
+
+               if (iedatalen < 4)
+                       goto cont;
+
+               iedata = ies + 2;
+
+               /* check WFA OUI, P2P subtype */
+               if (iedata[0] != 0x50 || iedata[1] != 0x6f ||
+                   iedata[2] != 0x9a || iedata[3] != 0x09)
+                       goto cont;
+
+               iedatalen -= 4;
+               iedata += 4;
+
+               /* check attribute continuation into this IE */
+               copy = min_t(unsigned int, attr_remaining, iedatalen);
+               if (copy && desired_attr) {
+                       desired_len += copy;
+                       if (out) {
+                               memcpy(out, iedata, min(bufsize, copy));
+                               out += min(bufsize, copy);
+                               bufsize -= min(bufsize, copy);
+                       }
+
+
+                       if (copy == attr_remaining)
+                               return desired_len;
+               }
+
+               attr_remaining -= copy;
+               if (attr_remaining)
+                       goto cont;
+
+               iedatalen -= copy;
+               iedata += copy;
+
+               while (iedatalen > 0) {
+                       u16 attr_len;
+
+                       /* P2P attribute ID & size must fit */
+                       if (iedatalen < 3)
+                               return -EILSEQ;
+                       desired_attr = iedata[0] == attr;
+                       attr_len = get_unaligned_le16(iedata + 1);
+                       iedatalen -= 3;
+                       iedata += 3;
+
+                       copy = min_t(unsigned int, attr_len, iedatalen);
+
+                       if (desired_attr) {
+                               desired_len += copy;
+                               if (out) {
+                                       memcpy(out, iedata, min(bufsize, copy));
+                                       out += min(bufsize, copy);
+                                       bufsize -= min(bufsize, copy);
+                               }
+
+                               if (copy == attr_len)
+                                       return desired_len;
+                       }
+
+                       iedata += copy;
+                       iedatalen -= copy;
+                       attr_remaining = attr_len - copy;
+               }
+
+ cont:
+               len -= ies[1] + 2;
+               ies += ies[1] + 2;
+       }
+
+       if (attr_remaining && desired_attr)
+               return -EILSEQ;
+
+       return -ENOENT;
+}
+EXPORT_SYMBOL(cfg80211_get_p2p_attr);
+
 int cfg80211_validate_beacon_int(struct cfg80211_registered_device *rdev,
                                 u32 beacon_int)
 {
index 6488d2dbc1d783bb34f3009fe8a8b81b05c1b5f9..f9680c9cf9b3d26fc828671054e8b2c1e1bff551 100644 (file)
@@ -784,6 +784,9 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
+       struct cfg80211_chan_def chandef = {
+               .width = NL80211_CHAN_WIDTH_20_NOHT,
+       };
        int freq, err;
 
        switch (wdev->iftype) {
@@ -797,8 +800,12 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
                        return freq;
                if (freq == 0)
                        return -EINVAL;
+               chandef.center_freq1 = freq;
+               chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
+               if (!chandef.chan)
+                       return -EINVAL;
                mutex_lock(&rdev->devlist_mtx);
-               err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
+               err = cfg80211_set_monitor_channel(rdev, &chandef);
                mutex_unlock(&rdev->devlist_mtx);
                return err;
        case NL80211_IFTYPE_MESH_POINT:
@@ -807,9 +814,12 @@ static int cfg80211_wext_siwfreq(struct net_device *dev,
                        return freq;
                if (freq == 0)
                        return -EINVAL;
+               chandef.center_freq1 = freq;
+               chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
+               if (!chandef.chan)
+                       return -EINVAL;
                mutex_lock(&rdev->devlist_mtx);
-               err = cfg80211_set_mesh_freq(rdev, wdev, freq,
-                                            NL80211_CHAN_NO_HT);
+               err = cfg80211_set_mesh_channel(rdev, wdev, &chandef);
                mutex_unlock(&rdev->devlist_mtx);
                return err;
        default:
@@ -823,8 +833,8 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
 {
        struct wireless_dev *wdev = dev->ieee80211_ptr;
        struct cfg80211_registered_device *rdev = wiphy_to_dev(wdev->wiphy);
-       struct ieee80211_channel *chan;
-       enum nl80211_channel_type channel_type;
+       struct cfg80211_chan_def chandef;
+       int ret;
 
        switch (wdev->iftype) {
        case NL80211_IFTYPE_STATION:
@@ -835,10 +845,10 @@ static int cfg80211_wext_giwfreq(struct net_device *dev,
                if (!rdev->ops->get_channel)
                        return -EINVAL;
 
-               chan = rdev_get_channel(rdev, wdev, &channel_type);
-               if (!chan)
-                       return -EINVAL;
-               freq->m = chan->center_freq;
+               ret = rdev_get_channel(rdev, wdev, &chandef);
+               if (ret)
+                       return ret;
+               freq->m = chandef.chan->center_freq;
                freq->e = 6;
                return 0;
        default:
@@ -895,7 +905,7 @@ static int cfg80211_wext_siwtxpower(struct net_device *dev,
                return 0;
        }
 
-       return rdev_set_tx_power(rdev, type, DBM_TO_MBM(dbm));
+       return rdev_set_tx_power(rdev, wdev, type, DBM_TO_MBM(dbm));
 }
 
 static int cfg80211_wext_giwtxpower(struct net_device *dev,
@@ -914,7 +924,7 @@ static int cfg80211_wext_giwtxpower(struct net_device *dev,
        if (!rdev->ops->get_tx_power)
                return -EOPNOTSUPP;
 
-       err = rdev_get_tx_power(rdev, &val);
+       err = rdev_get_tx_power(rdev, wdev, &val);
        if (err)
                return err;
 
index 1f773f668d1a557ae2712195ed510c3b9a2405b3..873af63187c0c52bdc194d0620a4b946560b6e9c 100644 (file)
@@ -119,7 +119,16 @@ int cfg80211_mgd_wext_siwfreq(struct net_device *dev,
         * channel we disconnected above and reconnect below.
         */
        if (chan && !wdev->wext.connect.ssid_len) {
-               err = cfg80211_set_monitor_channel(rdev, freq, NL80211_CHAN_NO_HT);
+               struct cfg80211_chan_def chandef = {
+                       .width = NL80211_CHAN_WIDTH_20_NOHT,
+                       .center_freq1 = freq,
+               };
+
+               chandef.chan = ieee80211_get_channel(&rdev->wiphy, freq);
+               if (chandef.chan)
+                       err = cfg80211_set_monitor_channel(rdev, &chandef);
+               else
+                       err = -EINVAL;
                goto out;
        }