rtlwifi: Add missing DMA buffer unmapping for PCI drivers
[linux-flexiantxendom0.git] / drivers / net / wireless / rtlwifi / pci.c
index baa2efe..d44d398 100644 (file)
  *
  *****************************************************************************/
 
+#include <linux/export.h>
 #include "core.h"
 #include "wifi.h"
 #include "pci.h"
 #include "base.h"
 #include "ps.h"
+#include "efuse.h"
 
 static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
-       INTEL_VENDOR_ID,
-       ATI_VENDOR_ID,
-       AMD_VENDOR_ID,
-       SIS_VENDOR_ID
+       PCI_VENDOR_ID_INTEL,
+       PCI_VENDOR_ID_ATI,
+       PCI_VENDOR_ID_AMD,
+       PCI_VENDOR_ID_SI
 };
 
+static const u8 ac_to_hwq[] = {
+       VO_QUEUE,
+       VI_QUEUE,
+       BE_QUEUE,
+       BK_QUEUE
+};
+
+static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
+                      struct sk_buff *skb)
+{
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       __le16 fc = rtl_get_fc(skb);
+       u8 queue_index = skb_get_queue_mapping(skb);
+
+       if (unlikely(ieee80211_is_beacon(fc)))
+               return BEACON_QUEUE;
+       if (ieee80211_is_mgmt(fc))
+               return MGNT_QUEUE;
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
+               if (ieee80211_is_nullfunc(fc))
+                       return HIGH_QUEUE;
+
+       return ac_to_hwq[queue_index];
+}
+
 /* Update PCI dependent default settings*/
 static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
 {
@@ -48,6 +75,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
+       u8 init_aspm;
 
        ppsc->reg_rfps_level = 0;
        ppsc->support_aspm = 0;
@@ -125,7 +153,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
                        bool support_backdoor = true;
                        ppsc->support_aspm = support_aspm;
 
-                       /*if(priv->oem_id == RT_CID_TOSHIBA &&
+                       /*if (priv->oem_id == RT_CID_TOSHIBA &&
                           !priv->ndis_adapter.amd_l1_patch)
                           support_backdoor = false; */
 
@@ -145,6 +173,13 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
                         ("switch case not process\n"));
                break;
        }
+
+       /* toshiba aspm issue, toshiba will set aspm selfly
+        * so we should not set aspm in driver */
+       pci_read_config_byte(rtlpci->pdev, 0x80, &init_aspm);
+       if (rtlpriv->rtlhal.hw_type == HARDWARE_TYPE_RTL8192SE &&
+               init_aspm == 0x43)
+               ppsc->support_aspm = false;
 }
 
 static bool _rtl_pci_platform_switch_device_pci_aspm(
@@ -152,28 +187,28 @@ static bool _rtl_pci_platform_switch_device_pci_aspm(
                        u8 value)
 {
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       bool bresult = false;
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
-       value |= 0x40;
+       if (rtlhal->hw_type != HARDWARE_TYPE_RTL8192SE)
+               value |= 0x40;
 
        pci_write_config_byte(rtlpci->pdev, 0x80, value);
 
-       return bresult;
+       return false;
 }
 
 /*When we set 0x01 to enable clk request. Set 0x0 to disable clk req.*/
 static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value)
 {
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       u8 buffer;
-       bool bresult = false;
-
-       buffer = value;
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
 
        pci_write_config_byte(rtlpci->pdev, 0x81, value);
-       bresult = true;
 
-       return bresult;
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
+               udelay(100);
+
+       return true;
 }
 
 /*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/
@@ -184,13 +219,16 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
-       u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
        u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
        /*Retrieve original configuration settings. */
        u8 linkctrl_reg = pcipriv->ndis_adapter.linkctrl_reg;
        u16 pcibridge_linkctrlreg = pcipriv->ndis_adapter.
                                pcibridge_linkctrlreg;
        u16 aspmlevel = 0;
+       u8 tmp_u1b = 0;
+
+       if (!ppsc->support_aspm)
+               return;
 
        if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
                RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
@@ -204,11 +242,8 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
                _rtl_pci_switch_clk_req(hw, 0x0);
        }
 
-       if (1) {
-               /*for promising device will in L0 state after an I/O. */
-               u8 tmp_u1b;
-               pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
-       }
+       /*for promising device will in L0 state after an I/O. */
+       pci_read_config_byte(rtlpci->pdev, 0x80, &tmp_u1b);
 
        /*Set corresponding value. */
        aspmlevel |= BIT(0) | BIT(1);
@@ -219,12 +254,10 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
        udelay(50);
 
        /*4 Disable Pci Bridge ASPM */
-       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-                                    pcicfg_addrport + (num4bytes << 2));
-       rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, pcibridge_linkctrlreg);
+       pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
+                             pcibridge_linkctrlreg);
 
        udelay(50);
-
 }
 
 /*
@@ -243,12 +276,14 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
        u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum;
        u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum;
        u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
-       u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
        u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
        u16 aspmlevel;
        u8 u_pcibridge_aspmsetting;
        u8 u_device_aspmsetting;
 
+       if (!ppsc->support_aspm)
+               return;
+
        if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
                RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
                         ("PCI(Bridge) UNKNOWN.\n"));
@@ -256,8 +291,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
        }
 
        /*4 Enable Pci Bridge ASPM */
-       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-                                    pcicfg_addrport + (num4bytes << 2));
 
        u_pcibridge_aspmsetting =
            pcipriv->ndis_adapter.pcibridge_linkctrlreg |
@@ -266,7 +299,8 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
        if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL)
                u_pcibridge_aspmsetting &= ~BIT(0);
 
-       rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting);
+       pci_write_config_byte(rtlpci->pdev, (num4bytes << 2),
+                             u_pcibridge_aspmsetting);
 
        RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
                 ("PlatformEnableASPM():PciBridge busnumber[%x], "
@@ -293,30 +327,23 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
                                             RT_RF_OFF_LEVL_CLK_REQ) ? 1 : 0);
                RT_SET_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_CLK_REQ);
        }
-       udelay(200);
+       udelay(100);
 }
 
 static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
 {
-       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
-       u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
+       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
 
        bool status = false;
        u8 offset_e0;
        unsigned offset_e4;
 
-       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-                       pcicfg_addrport + 0xE0);
-       rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, 0xA0);
+       pci_write_config_byte(rtlpci->pdev, 0xe0, 0xa0);
 
-       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-                       pcicfg_addrport + 0xE0);
-       rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &offset_e0);
+       pci_read_config_byte(rtlpci->pdev, 0xe0, &offset_e0);
 
        if (offset_e0 == 0xA0) {
-               rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-                                            pcicfg_addrport + 0xE4);
-               rtl_pci_raw_read_port_ulong(PCI_CONF_DATA, &offset_e4);
+               pci_read_config_dword(rtlpci->pdev, 0xe4, &offset_e4);
                if (offset_e4 & BIT(23))
                        status = true;
        }
@@ -327,17 +354,15 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
 static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
 {
        struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
        u8 capabilityoffset = pcipriv->ndis_adapter.pcibridge_pciehdr_offset;
-       u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
        u8 linkctrl_reg;
-       u8 num4bBytes;
+       u8 num4bbytes;
 
-       num4bBytes = (capabilityoffset + 0x10) / 4;
+       num4bbytes = (capabilityoffset + 0x10) / 4;
 
        /*Read  Link Control Register */
-       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-                                    pcicfg_addrport + (num4bBytes << 2));
-       rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &linkctrl_reg);
+       pci_read_config_byte(rtlpci->pdev, (num4bbytes << 2), &linkctrl_reg);
 
        pcipriv->ndis_adapter.pcibridge_linkctrlreg = linkctrl_reg;
 }
@@ -353,7 +378,7 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev,
        u8 linkctrl_reg;
 
        /*Link Control Register */
-       pos = pci_find_capability(pdev, PCI_CAP_ID_EXP);
+       pos = pci_pcie_cap(pdev);
        pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg);
        pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg;
 
@@ -369,7 +394,7 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev,
        pci_write_config_byte(pdev, 0x70f, tmp);
 }
 
-static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw)
+static void rtl_pci_init_aspm(struct ieee80211_hw *hw)
 {
        struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 
@@ -383,52 +408,6 @@ static void _rtl_pci_initialize_adapter_common(struct ieee80211_hw *hw)
 
 }
 
-static void rtl_pci_init_aspm(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;
-
-       _rtl_pci_initialize_adapter_common(hw);
-}
-
 static void _rtl_pci_io_handler_init(struct device *dev,
                                     struct ieee80211_hw *hw)
 {
@@ -450,6 +429,90 @@ static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw)
 {
 }
 
+static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
+               struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       u8 additionlen = FCS_LEN;
+       struct sk_buff *next_skb;
+
+       /* here open is 4, wep/tkip is 8, aes is 12*/
+       if (info->control.hw_key)
+               additionlen += info->control.hw_key->icv_len;
+
+       /* The most skb num is 6 */
+       tcb_desc->empkt_num = 0;
+       spin_lock_bh(&rtlpriv->locks.waitq_lock);
+       skb_queue_walk(&rtlpriv->mac80211.skb_waitq[tid], next_skb) {
+               struct ieee80211_tx_info *next_info;
+
+               next_info = IEEE80211_SKB_CB(next_skb);
+               if (next_info->flags & IEEE80211_TX_CTL_AMPDU) {
+                       tcb_desc->empkt_len[tcb_desc->empkt_num] =
+                               next_skb->len + additionlen;
+                       tcb_desc->empkt_num++;
+               } else {
+                       break;
+               }
+
+               if (skb_queue_is_last(&rtlpriv->mac80211.skb_waitq[tid],
+                                     next_skb))
+                       break;
+
+               if (tcb_desc->empkt_num >= 5)
+                       break;
+       }
+       spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+
+       return true;
+}
+
+/* just for early mode now */
+static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
+{
+       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 sk_buff *skb = NULL;
+       struct ieee80211_tx_info *info = NULL;
+       int tid;
+
+       if (!rtlpriv->rtlhal.earlymode_enable)
+               return;
+
+       /* we juse use em for BE/BK/VI/VO */
+       for (tid = 7; tid >= 0; tid--) {
+               u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)];
+               struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
+               while (!mac->act_scanning &&
+                      rtlpriv->psc.rfpwr_state == ERFON) {
+                       struct rtl_tcb_desc tcb_desc;
+                       memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
+
+                       spin_lock_bh(&rtlpriv->locks.waitq_lock);
+                       if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
+                          (ring->entries - skb_queue_len(&ring->queue) > 5)) {
+                               skb = skb_dequeue(&mac->skb_waitq[tid]);
+                       } else {
+                               spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+                               break;
+                       }
+                       spin_unlock_bh(&rtlpriv->locks.waitq_lock);
+
+                       /* Some macaddr can't do early mode. like
+                        * multicast/broadcast/no_qos data */
+                       info = IEEE80211_SKB_CB(skb);
+                       if (info->flags & IEEE80211_TX_CTL_AMPDU)
+                               _rtl_update_earlymode_info(hw, skb,
+                                                          &tcb_desc, tid);
+
+                       rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
+               }
+       }
+}
+
+
 static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -461,6 +524,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
                struct rtl_tx_desc *entry = &ring->desc[ring->idx];
                struct sk_buff *skb;
                struct ieee80211_tx_info *info;
+               __le16 fc;
+               u8 tid;
 
                u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
                                                          HW_DESC_OWN);
@@ -481,6 +546,10 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
                                                      HW_DESC_TXBUFF_ADDR),
                                 skb->len, PCI_DMA_TODEVICE);
 
+               /* remove early mode header */
+               if (rtlpriv->rtlhal.earlymode_enable)
+                       skb_pull(skb, EM_HDR_LEN);
+
                RT_TRACE(rtlpriv, (COMP_INTR | COMP_SEND), DBG_TRACE,
                         ("new ring->idx:%d, "
                          "free: skb_queue_len:%d, free: seq:%x\n",
@@ -488,6 +557,30 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
                          skb_queue_len(&ring->queue),
                          *(u16 *) (skb->data + 22)));
 
+               if (prio == TXCMD_QUEUE) {
+                       dev_kfree_skb(skb);
+                       goto tx_status_ok;
+
+               }
+
+               /* for sw LPS, just after NULL skb send out, we can
+                * sure AP kown we are sleeped, our we should not let
+                * rf to sleep*/
+               fc = rtl_get_fc(skb);
+               if (ieee80211_is_nullfunc(fc)) {
+                       if (ieee80211_has_pm(fc)) {
+                               rtlpriv->mac80211.offchan_delay = true;
+                               rtlpriv->psc.state_inap = 1;
+                       } else {
+                               rtlpriv->psc.state_inap = 0;
+                       }
+               }
+
+               /* update tid tx pkt num */
+               tid = rtl_get_tid(skb);
+               if (tid <= 7)
+                       rtlpriv->link_info.tidtx_inperiod[tid]++;
+
                info = IEEE80211_SKB_CB(skb);
                ieee80211_tx_info_clear_status(info);
 
@@ -510,15 +603,67 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
                                        skb_get_queue_mapping
                                        (skb));
                }
-
+tx_status_ok:
                skb = NULL;
        }
 
        if (((rtlpriv->link_info.num_rx_inperiod +
                rtlpriv->link_info.num_tx_inperiod) > 8) ||
                (rtlpriv->link_info.num_rx_inperiod > 2)) {
-               rtl_lps_leave(hw);
+               tasklet_schedule(&rtlpriv->works.ips_leave_tasklet);
+       }
+}
+
+static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
+                            struct ieee80211_rx_status rx_status)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+       __le16 fc = rtl_get_fc(skb);
+       bool unicast = false;
+       struct sk_buff *uskb = NULL;
+       u8 *pdata;
+
+
+       memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status));
+
+       if (is_broadcast_ether_addr(hdr->addr1)) {
+               ;/*TODO*/
+       } else if (is_multicast_ether_addr(hdr->addr1)) {
+               ;/*TODO*/
+       } else {
+               unicast = true;
+               rtlpriv->stats.rxbytesunicast += skb->len;
+       }
+
+       rtl_is_special_data(hw, skb, false);
+
+       if (ieee80211_is_data(fc)) {
+               rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX);
+
+               if (unicast)
+                       rtlpriv->link_info.num_rx_inperiod++;
        }
+
+       /* for sw lps */
+       rtl_swlps_beacon(hw, (void *)skb->data, skb->len);
+       rtl_recognize_peer(hw, (void *)skb->data, skb->len);
+       if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) &&
+           (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) &&
+            (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc)))
+               return;
+
+       if (unlikely(!rtl_action_proc(hw, skb, false)))
+               return;
+
+       uskb = dev_alloc_skb(skb->len + 128);
+       if (!uskb)
+               return;         /* exit if allocation failed */
+       memcpy(IEEE80211_SKB_RXCB(uskb), &rx_status, sizeof(rx_status));
+       pdata = (u8 *)skb_put(uskb, skb->len);
+       memcpy(pdata, skb->data, skb->len);
+
+       ieee80211_rx_irqsafe(hw, uskb);
 }
 
 static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
@@ -532,176 +677,112 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
        u8 own;
        u8 tmp_one;
        u32 bufferaddress;
-       bool unicast = false;
 
        struct rtl_stats stats = {
                .signal = 0,
                .noise = -98,
                .rate = 0,
        };
+       int index = rtlpci->rx_ring[rx_queue_idx].idx;
 
        /*RX NORMAL PKT */
        while (count--) {
                /*rx descriptor */
                struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[
-                               rtlpci->rx_ring[rx_queue_idx].idx];
+                               index];
                /*rx pkt */
                struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[
-                               rtlpci->rx_ring[rx_queue_idx].idx];
+                               index];
+               struct sk_buff *new_skb = NULL;
 
                own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
                                                       false, HW_DESC_OWN);
 
-               if (own) {
-                       /*wait data to be filled by hardware */
-                       return;
-               } else {
-                       struct ieee80211_hdr *hdr;
-                       __le16 fc;
-                       struct sk_buff *new_skb = NULL;
+               /*wait data to be filled by hardware */
+               if (own)
+                       break;
 
-                       rtlpriv->cfg->ops->query_rx_desc(hw, &stats,
-                                                        &rx_status,
-                                                        (u8 *) pdesc, skb);
+               rtlpriv->cfg->ops->query_rx_desc(hw, &stats,
+                                                &rx_status,
+                                                (u8 *) pdesc, skb);
 
-                       pci_unmap_single(rtlpci->pdev,
-                                        *((dma_addr_t *) skb->cb),
-                                        rtlpci->rxbuffersize,
-                                        PCI_DMA_FROMDEVICE);
+               if (stats.crc || stats.hwerror)
+                       goto done;
 
-                       skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
-                                                        false,
-                                                        HW_DESC_RXPKT_LEN));
-                       skb_reserve(skb,
-                                   stats.rx_drvinfo_size + stats.rx_bufshift);
+               new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
+               if (unlikely(!new_skb)) {
+                       RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
+                                DBG_DMESG,
+                                ("can't alloc skb for rx\n"));
+                       goto done;
+               }
 
-                       /*
-                        *NOTICE This can not be use for mac80211,
-                        *this is done in mac80211 code,
-                        *if you done here sec DHCP will fail
-                        *skb_trim(skb, skb->len - 4);
-                        */
+               pci_unmap_single(rtlpci->pdev,
+                                *((dma_addr_t *) skb->cb),
+                                rtlpci->rxbuffersize,
+                                PCI_DMA_FROMDEVICE);
 
-                       hdr = (struct ieee80211_hdr *)(skb->data);
-                       fc = hdr->frame_control;
-
-                       if (!stats.crc) {
-                               memcpy(IEEE80211_SKB_RXCB(skb), &rx_status,
-                                      sizeof(rx_status));
-
-                               if (is_broadcast_ether_addr(hdr->addr1))
-                                       ;/*TODO*/
-                               else {
-                                       if (is_multicast_ether_addr(hdr->addr1))
-                                               ;/*TODO*/
-                                       else {
-                                               unicast = true;
-                                               rtlpriv->stats.rxbytesunicast +=
-                                                   skb->len;
-                                       }
-                               }
-
-                               rtl_is_special_data(hw, skb, false);
-
-                               if (ieee80211_is_data(fc)) {
-                                       rtlpriv->cfg->ops->led_control(hw,
-                                                              LED_CTL_RX);
-
-                                       if (unicast)
-                                               rtlpriv->link_info.
-                                                   num_rx_inperiod++;
-                               }
-
-                               if (unlikely(!rtl_action_proc(hw, skb,
-                                   false))) {
-                                       dev_kfree_skb_any(skb);
-                               } else {
-                                       struct sk_buff *uskb = NULL;
-                                       u8 *pdata;
-                                       uskb = dev_alloc_skb(skb->len + 128);
-                                       if (!uskb) {
-                                               RT_TRACE(rtlpriv,
-                                                       (COMP_INTR | COMP_RECV),
-                                                       DBG_EMERG,
-                                                       ("can't alloc rx skb\n"));
-                                               goto done;
-                                       }
-                                       memcpy(IEEE80211_SKB_RXCB(uskb),
-                                                       &rx_status,
-                                                       sizeof(rx_status));
-                                       pdata = (u8 *)skb_put(uskb, skb->len);
-                                       memcpy(pdata, skb->data, skb->len);
-                                       dev_kfree_skb_any(skb);
-
-                                       ieee80211_rx_irqsafe(hw, uskb);
-                               }
-                       } else {
-                               dev_kfree_skb_any(skb);
-                       }
+               skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc, false,
+                       HW_DESC_RXPKT_LEN));
+               skb_reserve(skb, stats.rx_drvinfo_size + stats.rx_bufshift);
 
-                       if (((rtlpriv->link_info.num_rx_inperiod +
-                               rtlpriv->link_info.num_tx_inperiod) > 8) ||
-                               (rtlpriv->link_info.num_rx_inperiod > 2)) {
-                               rtl_lps_leave(hw);
-                       }
+               /*
+                * NOTICE This can not be use for mac80211,
+                * this is done in mac80211 code,
+                * if you done here sec DHCP will fail
+                * skb_trim(skb, skb->len - 4);
+                */
 
-                       new_skb = dev_alloc_skb(rtlpci->rxbuffersize);
-                       if (unlikely(!new_skb)) {
-                               RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV),
-                                        DBG_EMERG,
-                                        ("can't alloc skb for rx\n"));
-                               goto done;
-                       }
-                       skb = new_skb;
-                       /*skb->dev = dev; */
+               _rtl_receive_one(hw, skb, rx_status);
 
-                       rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci->
-                                                            rx_ring
-                                                            [rx_queue_idx].
-                                                            idx] = skb;
-                       *((dma_addr_t *) skb->cb) =
+               if (((rtlpriv->link_info.num_rx_inperiod +
+                       rtlpriv->link_info.num_tx_inperiod) > 8) ||
+                       (rtlpriv->link_info.num_rx_inperiod > 2)) {
+                       tasklet_schedule(&rtlpriv->works.ips_leave_tasklet);
+               }
+
+               dev_kfree_skb_any(skb);
+               skb = new_skb;
+
+               rtlpci->rx_ring[rx_queue_idx].rx_buf[index] = skb;
+               *((dma_addr_t *) skb->cb) =
                            pci_map_single(rtlpci->pdev, skb_tail_pointer(skb),
                                           rtlpci->rxbuffersize,
                                           PCI_DMA_FROMDEVICE);
 
-               }
 done:
-               bufferaddress = (u32)(*((dma_addr_t *) skb->cb));
+               bufferaddress = (*((dma_addr_t *)skb->cb));
                tmp_one = 1;
                rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
                                            HW_DESC_RXBUFF_ADDR,
                                            (u8 *)&bufferaddress);
-               rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
-                                           (u8 *)&tmp_one);
                rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
                                            HW_DESC_RXPKT_LEN,
                                            (u8 *)&rtlpci->rxbuffersize);
 
-               if (rtlpci->rx_ring[rx_queue_idx].idx ==
-                   rtlpci->rxringcount - 1)
+               if (index == rtlpci->rxringcount - 1)
                        rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
                                                    HW_DESC_RXERO,
                                                    (u8 *)&tmp_one);
 
-               rtlpci->rx_ring[rx_queue_idx].idx =
-                   (rtlpci->rx_ring[rx_queue_idx].idx + 1) %
-                   rtlpci->rxringcount;
+               rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
+                                           (u8 *)&tmp_one);
+
+               index = (index + 1) % rtlpci->rxringcount;
        }
 
+       rtlpci->rx_ring[rx_queue_idx].idx = index;
 }
 
 static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
 {
        struct ieee80211_hw *hw = dev_id;
        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));
        unsigned long flags;
        u32 inta = 0;
        u32 intb = 0;
 
-       if (rtlpci->irq_enabled == 0)
-               return IRQ_HANDLED;
-
        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 
        /*read ISR: 4/8bytes */
@@ -781,23 +862,36 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
                _rtl_pci_tx_isr(hw, VO_QUEUE);
        }
 
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE) {
+               if (inta & rtlpriv->cfg->maps[RTL_IMR_COMDOK]) {
+                       rtlpriv->link_info.num_tx_inperiod++;
+
+                       RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+                                       ("CMD TX OK interrupt!\n"));
+                       _rtl_pci_tx_isr(hw, TXCMD_QUEUE);
+               }
+       }
+
        /*<2> Rx related */
        if (inta & rtlpriv->cfg->maps[RTL_IMR_ROK]) {
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, ("Rx ok interrupt!\n"));
-               tasklet_schedule(&rtlpriv->works.irq_tasklet);
+               _rtl_pci_rx_interrupt(hw);
        }
 
        if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RDU])) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         ("rx descriptor unavailable!\n"));
-               tasklet_schedule(&rtlpriv->works.irq_tasklet);
+               _rtl_pci_rx_interrupt(hw);
        }
 
        if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n"));
-               tasklet_schedule(&rtlpriv->works.irq_tasklet);
+               _rtl_pci_rx_interrupt(hw);
        }
 
+       if (rtlpriv->rtlhal.earlymode_enable)
+               tasklet_schedule(&rtlpriv->works.irq_tasklet);
+
        spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
        return IRQ_HANDLED;
 
@@ -808,7 +902,12 @@ done:
 
 static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
 {
-       _rtl_pci_rx_interrupt(hw);
+       _rtl_pci_tx_chk_waitq(hw);
+}
+
+static void _rtl_pci_ips_leave_tasklet(struct ieee80211_hw *hw)
+{
+       rtl_lps_leave(hw);
 }
 
 static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
@@ -816,31 +915,34 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
-       struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[BEACON_QUEUE];
+       struct rtl8192_tx_ring *ring = NULL;
        struct ieee80211_hdr *hdr = NULL;
        struct ieee80211_tx_info *info = NULL;
        struct sk_buff *pskb = NULL;
        struct rtl_tx_desc *pdesc = NULL;
-       unsigned int queue_index;
+       struct rtl_tcb_desc tcb_desc;
        u8 temp_one = 1;
 
+       memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
        ring = &rtlpci->tx_ring[BEACON_QUEUE];
        pskb = __skb_dequeue(&ring->queue);
-       if (pskb)
+       if (pskb) {
+               struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+               pci_unmap_single(rtlpci->pdev, rtlpriv->cfg->ops->get_desc(
+                                (u8 *) entry, true, HW_DESC_TXBUFF_ADDR),
+                                pskb->len, PCI_DMA_TODEVICE);
                kfree_skb(pskb);
+       }
 
        /*NB: the beacon data buffer must be 32-bit aligned. */
        pskb = ieee80211_beacon_get(hw, mac->vif);
        if (pskb == NULL)
                return;
-       hdr = (struct ieee80211_hdr *)(pskb->data);
+       hdr = rtl_get_hdr(pskb);
        info = IEEE80211_SKB_CB(pskb);
-
-       queue_index = BEACON_QUEUE;
-
        pdesc = &ring->desc[0];
        rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
-                                       info, pskb, queue_index);
+               info, pskb, BEACON_QUEUE, &tcb_desc);
 
        __skb_queue_tail(&ring->queue, pskb);
 
@@ -882,7 +984,6 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
        struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-       struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(hw));
 
        rtlpci->up_first_time = true;
        rtlpci->being_init_adapter = false;
@@ -890,31 +991,20 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
        rtlhal->hw = hw;
        rtlpci->pdev = pdev;
 
-       ppsc->inactiveps = false;
-       ppsc->leisure_ps = true;
-       ppsc->fwctrl_lps = true;
-       ppsc->reg_fwctrl_lps = 3;
-       ppsc->reg_max_lps_awakeintvl = 5;
-
-       if (ppsc->reg_fwctrl_lps == 1)
-               ppsc->fwctrl_psmode = FW_PS_MIN_MODE;
-       else if (ppsc->reg_fwctrl_lps == 2)
-               ppsc->fwctrl_psmode = FW_PS_MAX_MODE;
-       else if (ppsc->reg_fwctrl_lps == 3)
-               ppsc->fwctrl_psmode = FW_PS_DTIM_MODE;
-
        /*Tx/Rx related var */
        _rtl_pci_init_trx_var(hw);
 
-        /*IBSS*/ mac->beacon_interval = 100;
+       /*IBSS*/ mac->beacon_interval = 100;
 
-        /*AMPDU*/ mac->min_space_cfg = 0;
+       /*AMPDU*/
+       mac->min_space_cfg = 0;
        mac->max_mss_density = 0;
        /*set sane AMPDU defaults */
        mac->current_ampdu_density = 7;
        mac->current_ampdu_factor = 3;
 
-        /*QOS*/ rtlpci->acm_method = eAcmWay2_SW;
+       /*QOS*/
+       rtlpci->acm_method = eAcmWay2_SW;
 
        /*task */
        tasklet_init(&rtlpriv->works.irq_tasklet,
@@ -923,6 +1013,9 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
        tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet,
                     (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet,
                     (unsigned long)hw);
+       tasklet_init(&rtlpriv->works.ips_leave_tasklet,
+                    (void (*)(unsigned long))_rtl_pci_ips_leave_tasklet,
+                    (unsigned long)hw);
 }
 
 static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
@@ -955,7 +1048,8 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
                 ("queue:%d, ring_addr:%p\n", prio, ring));
 
        for (i = 0; i < entries; i++) {
-               nextdescaddress = (u32) dma + ((i + 1) % entries) *
+               nextdescaddress = (u32) dma +
+                                             ((i + 1) % entries) *
                                              sizeof(*ring);
 
                rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]),
@@ -999,6 +1093,13 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
 
                rtlpci->rx_ring[rx_queue_idx].idx = 0;
 
+               /* If amsdu_8k is disabled, set buffersize to 4096. This
+                * change will reduce memory fragmentation.
+                */
+               if (rtlpci->rxbuffersize > 4096 &&
+                   rtlpriv->rtlhal.disable_amsdu_8k)
+                       rtlpci->rxbuffersize = 4096;
+
                for (i = 0; i < rtlpci->rxringcount; i++) {
                        struct sk_buff *skb =
                            dev_alloc_skb(rtlpci->rxbuffersize);
@@ -1020,7 +1121,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
                                           rtlpci->rxbuffersize,
                                           PCI_DMA_FROMDEVICE);
 
-                       bufferaddress = (u32)(*((dma_addr_t *)skb->cb));
+                       bufferaddress = (*((dma_addr_t *)skb->cb));
                        rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
                                                    HW_DESC_RXBUFF_ADDR,
                                                    (u8 *)&bufferaddress);
@@ -1059,10 +1160,12 @@ static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw,
                ring->idx = (ring->idx + 1) % ring->entries;
        }
 
-       pci_free_consistent(rtlpci->pdev,
-                           sizeof(*ring->desc) * ring->entries,
-                           ring->desc, ring->dma);
-       ring->desc = NULL;
+       if (ring->desc) {
+               pci_free_consistent(rtlpci->pdev,
+                                   sizeof(*ring->desc) * ring->entries,
+                                   ring->desc, ring->dma);
+               ring->desc = NULL;
+       }
 }
 
 static void _rtl_pci_free_rx_ring(struct rtl_pci *rtlpci)
@@ -1086,12 +1189,14 @@ static void _rtl_pci_free_rx_ring(struct rtl_pci *rtlpci)
                        kfree_skb(skb);
                }
 
-               pci_free_consistent(rtlpci->pdev,
+               if (rtlpci->rx_ring[rx_queue_idx].desc) {
+                       pci_free_consistent(rtlpci->pdev,
                                    sizeof(*rtlpci->rx_ring[rx_queue_idx].
                                           desc) * rtlpci->rxringcount,
                                    rtlpci->rx_ring[rx_queue_idx].desc,
                                    rtlpci->rx_ring[rx_queue_idx].dma);
-               rtlpci->rx_ring[rx_queue_idx].desc = NULL;
+                       rtlpci->rx_ring[rx_queue_idx].desc = NULL;
+               }
        }
 }
 
@@ -1203,72 +1308,73 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
        return 0;
 }
 
-static unsigned int _rtl_mac_to_hwqueue(__le16 fc,
-               unsigned int mac80211_queue_index)
+static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
+                                       struct sk_buff *skb)
 {
-       unsigned int hw_queue_index;
-
-       if (unlikely(ieee80211_is_beacon(fc))) {
-               hw_queue_index = BEACON_QUEUE;
-               goto out;
-       }
-
-       if (ieee80211_is_mgmt(fc)) {
-               hw_queue_index = MGNT_QUEUE;
-               goto out;
-       }
-
-       switch (mac80211_queue_index) {
-       case 0:
-               hw_queue_index = VO_QUEUE;
-               break;
-       case 1:
-               hw_queue_index = VI_QUEUE;
-               break;
-       case 2:
-               hw_queue_index = BE_QUEUE;
-               break;
-       case 3:
-               hw_queue_index = BK_QUEUE;
-               break;
-       default:
-               hw_queue_index = BE_QUEUE;
-               RT_ASSERT(false, ("QSLT_BE queue, skb_queue:%d\n",
-                                 mac80211_queue_index));
-               break;
-       }
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = info->control.sta;
+       struct rtl_sta_info *sta_entry = NULL;
+       u8 tid = rtl_get_tid(skb);
+
+       if (!sta)
+               return false;
+       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+
+       if (!rtlpriv->rtlhal.earlymode_enable)
+               return false;
+       if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL)
+               return false;
+       if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE)
+               return false;
+       if (tid > 7)
+               return false;
+
+       /* maybe every tid should be checked */
+       if (!rtlpriv->link_info.higher_busytxtraffic[tid])
+               return false;
+
+       spin_lock_bh(&rtlpriv->locks.waitq_lock);
+       skb_queue_tail(&rtlpriv->mac80211.skb_waitq[tid], skb);
+       spin_unlock_bh(&rtlpriv->locks.waitq_lock);
 
-out:
-       return hw_queue_index;
+       return true;
 }
 
-static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
+static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
+               struct rtl_tcb_desc *ptcb_desc)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
+       struct rtl_sta_info *sta_entry = NULL;
        struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
+       struct ieee80211_sta *sta = info->control.sta;
        struct rtl8192_tx_ring *ring;
        struct rtl_tx_desc *pdesc;
        u8 idx;
-       unsigned int queue_index, hw_queue;
+       u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb);
        unsigned long flags;
-       struct ieee80211_hdr *hdr = (struct ieee80211_hdr *)(skb->data);
-       __le16 fc = hdr->frame_control;
+       struct ieee80211_hdr *hdr = rtl_get_hdr(skb);
+       __le16 fc = rtl_get_fc(skb);
        u8 *pda_addr = hdr->addr1;
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        /*ssn */
-       u8 *qc = NULL;
        u8 tid = 0;
        u16 seq_number = 0;
        u8 own;
        u8 temp_one = 1;
 
-       if (ieee80211_is_mgmt(fc))
-               rtl_tx_mgmt_proc(hw, skb);
-       rtl_action_proc(hw, skb, true);
+       if (ieee80211_is_auth(fc)) {
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
+               rtl_ips_nic_on(hw);
+       }
+
+       if (rtlpriv->psc.sw_ps_enabled) {
+               if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) &&
+                       !ieee80211_has_pm(fc))
+                       hdr->frame_control |= cpu_to_le16(IEEE80211_FCTL_PM);
+       }
 
-       queue_index = skb_get_queue_mapping(skb);
-       hw_queue = _rtl_mac_to_hwqueue(fc, queue_index);
+       rtl_action_proc(hw, skb, true);
 
        if (is_multicast_ether_addr(pda_addr))
                rtlpriv->stats.txbytesmulticast += skb->len;
@@ -1278,7 +1384,6 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                rtlpriv->stats.txbytesunicast += skb->len;
 
        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
-
        ring = &rtlpci->tx_ring[hw_queue];
        if (hw_queue != BEACON_QUEUE)
                idx = (ring->idx + skb_queue_len(&ring->queue)) %
@@ -1301,43 +1406,30 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
                return skb->len;
        }
 
-       /*
-        *if(ieee80211_is_nullfunc(fc)) {
-        *      spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-        *      return 1;
-        *}
-        */
-
        if (ieee80211_is_data_qos(fc)) {
-               qc = ieee80211_get_qos_ctl(hdr);
-               tid = qc[0] & IEEE80211_QOS_CTL_TID_MASK;
-
-               seq_number = mac->tids[tid].seq_number;
-               seq_number &= IEEE80211_SCTL_SEQ;
-               /*
-                *hdr->seq_ctrl = hdr->seq_ctrl &
-                *cpu_to_le16(IEEE80211_SCTL_FRAG);
-                *hdr->seq_ctrl |= cpu_to_le16(seq_number);
-                */
-
-               seq_number += 1;
+               tid = rtl_get_tid(skb);
+               if (sta) {
+                       sta_entry = (struct rtl_sta_info *)sta->drv_priv;
+                       seq_number = (le16_to_cpu(hdr->seq_ctrl) &
+                                     IEEE80211_SCTL_SEQ) >> 4;
+                       seq_number += 1;
+
+                       if (!ieee80211_has_morefrags(hdr->frame_control))
+                               sta_entry->tids[tid].seq_number = seq_number;
+               }
        }
 
        if (ieee80211_is_data(fc))
                rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
 
-       rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
-                                       info, skb, hw_queue);
+       rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
+                       info, skb, hw_queue, ptcb_desc);
 
        __skb_queue_tail(&ring->queue, skb);
 
-       rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true,
+       rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true,
                                    HW_DESC_OWN, (u8 *)&temp_one);
 
-       if (!ieee80211_has_morefrags(hdr->frame_control)) {
-               if (qc)
-                       mac->tids[tid].seq_number = seq_number;
-       }
 
        if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
            hw_queue != BEACON_QUEUE) {
@@ -1359,6 +1451,35 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb)
        return 0;
 }
 
+static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
+{
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+       struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+       u16 i = 0;
+       int queue_id;
+       struct rtl8192_tx_ring *ring;
+
+       for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
+               u32 queue_len;
+               ring = &pcipriv->dev.tx_ring[queue_id];
+               queue_len = skb_queue_len(&ring->queue);
+               if (queue_len == 0 || queue_id == BEACON_QUEUE ||
+                       queue_id == TXCMD_QUEUE) {
+                       queue_id--;
+                       continue;
+               } else {
+                       msleep(20);
+                       i++;
+               }
+
+               /* we just wait 1s for all queues */
+               if (rtlpriv->psc.rfpwr_state == ERFOFF ||
+                       is_hal_stop(rtlhal) || i >= 200)
+                       return;
+       }
+}
+
 static void rtl_pci_deinit(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1368,6 +1489,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw)
 
        synchronize_irq(rtlpci->pdev->irq);
        tasklet_kill(&rtlpriv->works.irq_tasklet);
+       tasklet_kill(&rtlpriv->works.ips_leave_tasklet);
 
        flush_workqueue(rtlpriv->works.rtl_wq);
        destroy_workqueue(rtlpriv->works.rtl_wq);
@@ -1415,7 +1537,7 @@ static int rtl_pci_start(struct ieee80211_hw *hw)
 
        rtl_init_rx_config(hw);
 
-       /*should after adapter start and interrupt enable. */
+       /*should be after adapter start and interrupt enable. */
        set_hal_start(rtlhal);
 
        RT_CLEAR_PS_LEVEL(ppsc, RT_RF_OFF_LEVL_HALT_NIC);
@@ -1436,12 +1558,13 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
        u8 RFInProgressTimeOut = 0;
 
        /*
-        *should before disable interrrupt&adapter
+        *should be before disable interrupt&adapter
         *and will do it immediately.
         */
        set_hal_stop(rtlhal);
 
        rtlpriv->cfg->ops->disable_interrupt(hw);
+       tasklet_kill(&rtlpriv->works.ips_leave_tasklet);
 
        spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
        while (ppsc->rfchange_inprogress) {
@@ -1477,13 +1600,26 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
        struct pci_dev *bridge_pdev = pdev->bus->self;
        u16 venderid;
        u16 deviceid;
+       u8 revisionid;
        u16 irqline;
        u8 tmp;
 
+       pcipriv->ndis_adapter.pcibridge_vendor = PCI_BRIDGE_VENDOR_UNKNOWN;
        venderid = pdev->vendor;
        deviceid = pdev->device;
+       pci_read_config_byte(pdev, 0x8, &revisionid);
        pci_read_config_word(pdev, 0x3C, &irqline);
 
+       /* PCI ID 0x10ec:0x8192 occurs for both RTL8192E, which uses
+        * r8192e_pci, and RTL8192SE, which uses this driver. If the
+        * revision ID is RTL_PCI_REVISION_ID_8192PCIE (0x01), then
+        * the correct driver is r8192e_pci, thus this routine should
+        * return false.
+        */
+       if (deviceid == RTL_PCI_8192SE_DID &&
+           revisionid == RTL_PCI_REVISION_ID_8192PCIE)
+               return false;
+
        if (deviceid == RTL_PCI_8192_DID ||
            deviceid == RTL_PCI_0044_DID ||
            deviceid == RTL_PCI_0047_DID ||
@@ -1492,7 +1628,7 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
            deviceid == RTL_PCI_8173_DID ||
            deviceid == RTL_PCI_8172_DID ||
            deviceid == RTL_PCI_8171_DID) {
-               switch (pdev->revision) {
+               switch (revisionid) {
                case RTL_PCI_REVISION_ID_8192PCIE:
                        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
                                 ("8192 PCI-E is found - "
@@ -1521,6 +1657,12 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
                RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
                         ("8192C PCI-E is found - "
                          "vid/did=%x/%x\n", venderid, deviceid));
+       } else if (deviceid == RTL_PCI_8192DE_DID ||
+                  deviceid == RTL_PCI_8192DE_DID2) {
+               rtlhal->hw_type = HARDWARE_TYPE_RTL8192DE;
+               RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                        ("8192D PCI-E is found - "
+                         "vid/did=%x/%x\n", venderid, deviceid));
        } else {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
                         ("Err: Unknown device -"
@@ -1529,20 +1671,41 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
                rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE;
        }
 
+       if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192DE) {
+               if (revisionid == 0 || revisionid == 1) {
+                       if (revisionid == 0) {
+                               RT_TRACE(rtlpriv, COMP_INIT,
+                                        DBG_LOUD, ("Find 92DE MAC0.\n"));
+                               rtlhal->interfaceindex = 0;
+                       } else if (revisionid == 1) {
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                                       ("Find 92DE MAC1.\n"));
+                               rtlhal->interfaceindex = 1;
+                       }
+               } else {
+                       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+                               ("Unknown device - "
+                               "VendorID/DeviceID=%x/%x, Revision=%x\n",
+                               venderid, deviceid, revisionid));
+                       rtlhal->interfaceindex = 0;
+               }
+       }
        /*find bus info */
        pcipriv->ndis_adapter.busnumber = pdev->bus->number;
        pcipriv->ndis_adapter.devnumber = PCI_SLOT(pdev->devfn);
        pcipriv->ndis_adapter.funcnumber = PCI_FUNC(pdev->devfn);
 
-       /*find bridge info */
-       pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
-       for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) {
-               if (bridge_pdev->vendor == pcibridge_vendors[tmp]) {
-                       pcipriv->ndis_adapter.pcibridge_vendor = tmp;
-                       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                                ("Pci Bridge Vendor is found index: %d\n",
-                                 tmp));
-                       break;
+       if (bridge_pdev) {
+               /*find bridge info if available */
+               pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
+               for (tmp = 0; tmp < PCI_BRIDGE_VENDOR_MAX; tmp++) {
+                       if (bridge_pdev->vendor == pcibridge_vendors[tmp]) {
+                               pcipriv->ndis_adapter.pcibridge_vendor = tmp;
+                               RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+                                        ("Pci Bridge Vendor is found index:"
+                                        " %d\n", tmp));
+                               break;
+                       }
                }
        }
 
@@ -1556,10 +1719,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
                    PCI_FUNC(bridge_pdev->devfn);
                pcipriv->ndis_adapter.pcibridge_pciehdr_offset =
                    pci_pcie_cap(bridge_pdev);
-               pcipriv->ndis_adapter.pcicfg_addrport =
-                   (pcipriv->ndis_adapter.pcibridge_busnum << 16) |
-                   (pcipriv->ndis_adapter.pcibridge_devnum << 11) |
-                   (pcipriv->ndis_adapter.pcibridge_funcnum << 8) | (1 << 31);
                pcipriv->ndis_adapter.num4bytes =
                    (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10) / 4;
 
@@ -1642,6 +1801,11 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
        pcipriv = (void *)rtlpriv->priv;
        pcipriv->dev.pdev = pdev;
 
+       /* init cfg & intf_ops */
+       rtlpriv->rtlhal.interface = INTF_PCI;
+       rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
+       rtlpriv->intf_ops = &rtl_pci_ops;
+
        /*
         *init dbgp flags before all
         *other functions, because we will
@@ -1659,13 +1823,14 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
                return err;
        }
 
-       pmem_start = pci_resource_start(pdev, 2);
-       pmem_len = pci_resource_len(pdev, 2);
-       pmem_flags = pci_resource_flags(pdev, 2);
+       pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
+       pmem_len = pci_resource_len(pdev, rtlpriv->cfg->bar_id);
+       pmem_flags = pci_resource_flags(pdev, rtlpriv->cfg->bar_id);
 
        /*shared mem start */
        rtlpriv->io.pci_mem_start =
-                       (unsigned long)pci_iomap(pdev, 2, pmem_len);
+                       (unsigned long)pci_iomap(pdev,
+                       rtlpriv->cfg->bar_id, pmem_len);
        if (rtlpriv->io.pci_mem_start == 0) {
                RT_ASSERT(false, ("Can't map PCI mem\n"));
                goto fail2;
@@ -1684,13 +1849,9 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
        pci_write_config_byte(pdev, 0x04, 0x06);
        pci_write_config_byte(pdev, 0x04, 0x07);
 
-       /* init cfg & intf_ops */
-       rtlpriv->rtlhal.interface = INTF_PCI;
-       rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
-       rtlpriv->intf_ops = &rtl_pci_ops;
-
        /* find adapter */
-       _rtl_pci_find_adapter(pdev, hw);
+       if (!_rtl_pci_find_adapter(pdev, hw))
+               goto fail3;
 
        /* Init IO handler */
        _rtl_pci_io_handler_init(&pdev->dev, hw);
@@ -1806,7 +1967,6 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
 
        rtl_pci_deinit(hw);
        rtl_deinit_core(hw);
-       rtlpriv->cfg->ops->deinit_sw_leds(hw);
        _rtl_pci_io_handler_release(hw);
        rtlpriv->cfg->ops->deinit_sw_vars(hw);
 
@@ -1821,6 +1981,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
        }
 
        pci_disable_device(pdev);
+
+       rtl_pci_disable_aspm(hw);
+
        pci_set_drvdata(pdev, NULL);
 
        ieee80211_free_hw(hw);
@@ -1842,38 +2005,39 @@ call rtl_mac_stop() from the mac80211
 suspend function first, So there is
 no need to call hw_disable here.
 ****************************************/
-int rtl_pci_suspend(struct pci_dev *pdev, pm_message_t state)
+int rtl_pci_suspend(struct device *dev)
 {
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
+
+       rtlpriv->cfg->ops->hw_suspend(hw);
+       rtl_deinit_rfkill(hw);
 
        return 0;
 }
 EXPORT_SYMBOL(rtl_pci_suspend);
 
-int rtl_pci_resume(struct pci_dev *pdev)
+int rtl_pci_resume(struct device *dev)
 {
-       int ret;
-
-       pci_set_power_state(pdev, PCI_D0);
-       ret = pci_enable_device(pdev);
-       if (ret) {
-               RT_ASSERT(false, ("ERR: <======\n"));
-               return ret;
-       }
-
-       pci_restore_state(pdev);
+       struct pci_dev *pdev = to_pci_dev(dev);
+       struct ieee80211_hw *hw = pci_get_drvdata(pdev);
+       struct rtl_priv *rtlpriv = rtl_priv(hw);
 
+       rtlpriv->cfg->ops->hw_resume(hw);
+       rtl_init_rfkill(hw);
        return 0;
 }
 EXPORT_SYMBOL(rtl_pci_resume);
 
 struct rtl_intf_ops rtl_pci_ops = {
+       .read_efuse_byte = read_efuse_byte,
        .adapter_start = rtl_pci_start,
        .adapter_stop = rtl_pci_stop,
        .adapter_tx = rtl_pci_tx,
+       .flush = rtl_pci_flush,
        .reset_trx_ring = rtl_pci_reset_trx_ring,
+       .waitq_insert = rtl_pci_tx_chk_waitq_insert,
 
        .disable_aspm = rtl_pci_disable_aspm,
        .enable_aspm = rtl_pci_enable_aspm,