rtlwifi: Add missing DMA buffer unmapping for PCI drivers
[linux-flexiantxendom0.git] / drivers / net / wireless / rtlwifi / pci.c
index aeb0901..d44d398 100644 (file)
@@ -27,6 +27,7 @@
  *
  *****************************************************************************/
 
+#include <linux/export.h>
 #include "core.h"
 #include "wifi.h"
 #include "pci.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[] = {
@@ -48,11 +49,11 @@ static const u8 ac_to_hwq[] = {
        BK_QUEUE
 };
 
-u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
+static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
                       struct sk_buff *skb)
 {
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
-       u16 fc = rtl_get_fc(skb);
+       __le16 fc = rtl_get_fc(skb);
        u8 queue_index = skb_get_queue_mapping(skb);
 
        if (unlikely(ieee80211_is_beacon(fc)))
@@ -181,71 +182,6 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
                ppsc->support_aspm = false;
 }
 
-/*Disable L0s dirtectly. We will disable host L0s by default. */
-void rtl_pci_disable_host_l0s(struct ieee80211_hw *hw)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
-       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       u8 pcibridge_busnum = pcipriv->ndis_adapter.pcibridge_busnum;
-       u8 pcibridge_devnum = pcipriv->ndis_adapter.pcibridge_devnum;
-       u8 pcibridge_funcnum = pcipriv->ndis_adapter.pcibridge_funcnum;
-       u32 pcicfg_addrport = pcipriv->ndis_adapter.pcicfg_addrport;
-       u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
-       u8 u_pcibridge_aspmsetting = 0;
-
-       /*Read  Link Control Register */
-       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-                                    pcicfg_addrport + (num4bytes << 2));
-       rtl_pci_raw_read_port_uchar(PCI_CONF_DATA, &u_pcibridge_aspmsetting);
-
-       if (u_pcibridge_aspmsetting & BIT(0))
-               u_pcibridge_aspmsetting &= ~(BIT(0));
-
-       rtl_pci_raw_write_port_ulong(PCI_CONF_ADDRESS,
-                                    pcicfg_addrport + (num4bytes << 2));
-       rtl_pci_raw_write_port_uchar(PCI_CONF_DATA, u_pcibridge_aspmsetting);
-
-       udelay(50);
-
-       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-                ("PciBridge busnumber[%x], DevNumbe[%x], "
-                 "funcnumber[%x], Write reg[%x] = %lx\n",
-                 pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum,
-                 (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
-                 (pcipriv->ndis_adapter.pcibridge_linkctrlreg |
-                  (rtlpci->const_devicepci_aspm_setting & ~BIT(0)))));
-}
-
-/*Enable rtl8192ce backdoor to control ASPM and clock request.*/
-bool rtl_pci_enable_back_door(struct ieee80211_hw *hw)
-{
-       struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
-       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
-       bool bresult = true;
-       u8 value;
-
-       pci_read_config_byte(rtlpci->pdev, 0x70f, &value);
-
-       /*0x70f BIT(7) is used to control L0S */
-       if (pcibridge_vendor == PCI_BRIDGE_VENDOR_INTEL) {
-               value |= BIT(7);
-       } else {
-               /*Set 0x70f to 0x23 when non-Intel platform. */
-               value = 0x23;
-       }
-
-       pci_write_config_byte(rtlpci->pdev, 0x70f, value);
-
-       pci_read_config_byte(rtlpci->pdev, 0x719, &value);
-       /*0x719 BIT(3) is for L1 BIT(4) is for clock request */
-       value |= (BIT(3) | BIT(4));
-       pci_write_config_byte(rtlpci->pdev, 0x719, value);
-
-       return bresult;
-}
-
 static bool _rtl_pci_platform_switch_device_pci_aspm(
                        struct ieee80211_hw *hw,
                        u8 value)
@@ -283,7 +219,6 @@ 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;
@@ -319,9 +254,8 @@ 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);
 }
@@ -342,7 +276,6 @@ 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;
@@ -358,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 |
@@ -368,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], "
@@ -400,25 +332,18 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
 
 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;
        }
@@ -426,20 +351,18 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
        return status;
 }
 
-void rtl_pci_get_linkcontrol_field(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;
 
        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;
 }
@@ -455,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;
 
@@ -553,7 +476,7 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct sk_buff *skb = NULL;
        struct ieee80211_tx_info *info = NULL;
-       int tid; /* should be int */
+       int tid;
 
        if (!rtlpriv->rtlhal.earlymode_enable)
                return;
@@ -618,9 +541,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
 
                skb = __skb_dequeue(&ring->queue);
                pci_unmap_single(rtlpci->pdev,
-                                le32_to_cpu(rtlpriv->cfg->ops->
+                                rtlpriv->cfg->ops->
                                             get_desc((u8 *) entry, true,
-                                                     HW_DESC_TXBUFF_ADDR)),
+                                                     HW_DESC_TXBUFF_ADDR),
                                 skb->len, PCI_DMA_TODEVICE);
 
                /* remove early mode header */
@@ -646,7 +569,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
                fc = rtl_get_fc(skb);
                if (ieee80211_is_nullfunc(fc)) {
                        if (ieee80211_has_pm(fc)) {
-                               rtlpriv->mac80211.offchan_deley = true;
+                               rtlpriv->mac80211.offchan_delay = true;
                                rtlpriv->psc.state_inap = 1;
                        } else {
                                rtlpriv->psc.state_inap = 0;
@@ -687,10 +610,62 @@ tx_status_ok:
        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)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -702,254 +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 = rtl_get_hdr(skb);
-                       fc = rtl_get_fc(skb);
-
-                       if (!stats.crc || !stats.hwerror) {
-                               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))) {
-                                       dev_kfree_skb_any(skb);
-                               } else {
-                                       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);
-                                               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_DMESG,
-                                        ("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 = cpu_to_le32(*((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;
-       }
-
-}
-
-void _rtl_pci_tx_interrupt(struct ieee80211_hw *hw)
-{
-       struct rtl_priv *rtlpriv = rtl_priv(hw);
-       struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
-       int prio;
-
-       for (prio = 0; prio < RTL_PCI_MAX_TX_QUEUE_COUNT; prio++) {
-               struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[prio];
-
-               while (skb_queue_len(&ring->queue)) {
-                       struct rtl_tx_desc *entry = &ring->desc[ring->idx];
-                       struct sk_buff *skb;
-                       struct ieee80211_tx_info *info;
-                       u8 own;
-
-                       /*
-                        *beacon packet will only use the first
-                        *descriptor defautly, and the own may not
-                        *be cleared by the hardware, and
-                        *beacon will free in prepare beacon
-                        */
-                       if (prio == BEACON_QUEUE || prio == TXCMD_QUEUE ||
-                           prio == HCCA_QUEUE)
-                               break;
-
-                       own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry,
-                                                              true,
-                                                              HW_DESC_OWN);
-
-                       if (own)
-                               break;
-
-                       skb = __skb_dequeue(&ring->queue);
-                       pci_unmap_single(rtlpci->pdev,
-                                        le32_to_cpu(rtlpriv->cfg->ops->
-                                                    get_desc((u8 *) entry,
-                                                         true,
-                                                         HW_DESC_TXBUFF_ADDR)),
-                                        skb->len, PCI_DMA_TODEVICE);
-
-                       ring->idx = (ring->idx + 1) % ring->entries;
-
-                       info = IEEE80211_SKB_CB(skb);
-                       ieee80211_tx_info_clear_status(info);
-
-                       info->flags |= IEEE80211_TX_STAT_ACK;
-                       /*info->status.rates[0].count = 1; */
-
-                       ieee80211_tx_status_irqsafe(hw, skb);
-
-                       if ((ring->entries - skb_queue_len(&ring->queue))
-                           == 2 && prio != BEACON_QUEUE) {
-                               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                                        ("more desc left, wake "
-                                         "skb_queue@%d,ring->idx = %d,"
-                                         "skb_queue_len = 0x%d\n",
-                                         prio, ring->idx,
-                                         skb_queue_len(&ring->queue)));
-
-                               ieee80211_wake_queue(hw,
-                                                    skb_get_queue_mapping
-                                                    (skb));
-                       }
+               rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
+                                           (u8 *)&tmp_one);
 
-                       skb = NULL;
-               }
+               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 */
@@ -1072,6 +905,11 @@ static void _rtl_pci_irq_tasklet(struct ieee80211_hw *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)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
@@ -1088,8 +926,13 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        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);
@@ -1170,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,
@@ -1202,9 +1048,9 @@ 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 = cpu_to_le32((u32) dma +
-                                             ((i + 11) % entries) *
-                                             sizeof(*ring));
+               nextdescaddress = (u32) dma +
+                                             ((i + 1) % entries) *
+                                             sizeof(*ring);
 
                rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]),
                                            true, HW_DESC_TX_NEXTDESC_ADDR,
@@ -1247,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);
@@ -1268,7 +1121,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
                                           rtlpci->rxbuffersize,
                                           PCI_DMA_FROMDEVICE);
 
-                       bufferaddress = cpu_to_le32(*((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);
@@ -1299,18 +1152,20 @@ static void _rtl_pci_free_tx_ring(struct ieee80211_hw *hw,
                struct sk_buff *skb = __skb_dequeue(&ring->queue);
 
                pci_unmap_single(rtlpci->pdev,
-                                le32_to_cpu(rtlpriv->cfg->
+                                rtlpriv->cfg->
                                             ops->get_desc((u8 *) entry, true,
-                                                  HW_DESC_TXBUFF_ADDR)),
+                                                  HW_DESC_TXBUFF_ADDR),
                                 skb->len, PCI_DMA_TODEVICE);
                kfree_skb(skb);
                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)
@@ -1334,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;
+               }
        }
 }
 
@@ -1433,11 +1290,11 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
                                    __skb_dequeue(&ring->queue);
 
                                pci_unmap_single(rtlpci->pdev,
-                                                le32_to_cpu(rtlpriv->cfg->ops->
+                                                rtlpriv->cfg->ops->
                                                         get_desc((u8 *)
                                                         entry,
                                                         true,
-                                                        HW_DESC_TXBUFF_ADDR)),
+                                                        HW_DESC_TXBUFF_ADDR),
                                                 skb->len, PCI_DMA_TODEVICE);
                                kfree_skb(skb);
                                ring->idx = (ring->idx + 1) % ring->entries;
@@ -1484,7 +1341,7 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
        return true;
 }
 
-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);
@@ -1623,7 +1480,7 @@ static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
        }
 }
 
-void rtl_pci_deinit(struct ieee80211_hw *hw)
+static void rtl_pci_deinit(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1632,13 +1489,14 @@ 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);
 
 }
 
-int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev)
+static int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        int err;
@@ -1655,7 +1513,7 @@ int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev)
        return 1;
 }
 
-int rtl_pci_start(struct ieee80211_hw *hw)
+static int rtl_pci_start(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -1679,7 +1537,7 @@ 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);
@@ -1690,7 +1548,7 @@ int rtl_pci_start(struct ieee80211_hw *hw)
        return 0;
 }
 
-void rtl_pci_stop(struct ieee80211_hw *hw)
+static void rtl_pci_stop(struct ieee80211_hw *hw)
 {
        struct rtl_priv *rtlpriv = rtl_priv(hw);
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1700,12 +1558,13 @@ 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) {
@@ -1745,11 +1604,22 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
        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 ||
@@ -1825,15 +1695,17 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
        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;
+                       }
                }
        }
 
@@ -1845,10 +1717,6 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
                    PCI_SLOT(bridge_pdev->devfn);
                pcipriv->ndis_adapter.pcibridge_funcnum =
                    PCI_FUNC(bridge_pdev->devfn);
-               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.pcibridge_pciehdr_offset =
                    pci_pcie_cap(bridge_pdev);
                pcipriv->ndis_adapter.num4bytes =
@@ -1982,7 +1850,8 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
        pci_write_config_byte(pdev, 0x04, 0x07);
 
        /* 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);
@@ -2136,36 +2005,25 @@ 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)
 {
+       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);
 
-       pci_save_state(pdev);
-       pci_disable_device(pdev);
-       pci_set_power_state(pdev, PCI_D3hot);
        return 0;
 }
 EXPORT_SYMBOL(rtl_pci_suspend);
 
-int rtl_pci_resume(struct pci_dev *pdev)
+int rtl_pci_resume(struct device *dev)
 {
-       int ret;
+       struct pci_dev *pdev = to_pci_dev(dev);
        struct ieee80211_hw *hw = pci_get_drvdata(pdev);
        struct rtl_priv *rtlpriv = rtl_priv(hw);
 
-       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);
-
        rtlpriv->cfg->ops->hw_resume(hw);
        rtl_init_rfkill(hw);
        return 0;