Update to 3.4-final.
[linux-flexiantxendom0-3.2.10.git] / drivers / net / wireless / rtlwifi / pci.c
index 89100e7..67f9430 100644 (file)
@@ -1,6 +1,6 @@
 /******************************************************************************
  *
- * Copyright(c) 2009-2010  Realtek Corporation.
+ * Copyright(c) 2009-2012  Realtek Corporation.
  *
  * This program is free software; you can redistribute it and/or modify it
  * under the terms of version 2 of the GNU General Public License as
  *
  *****************************************************************************/
 
-#include "core.h"
 #include "wifi.h"
+#include "core.h"
 #include "pci.h"
 #include "base.h"
 #include "ps.h"
 #include "efuse.h"
+#include <linux/export.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[] = {
@@ -77,7 +78,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
        u8 init_aspm;
 
        ppsc->reg_rfps_level = 0;
-       ppsc->support_aspm = 0;
+       ppsc->support_aspm = false;
 
        /*Update PCI ASPM setting */
        ppsc->const_amdpci_aspm = rtlpci->const_amdpci_aspm;
@@ -169,7 +170,7 @@ static void _rtl_pci_update_default_setting(struct ieee80211_hw *hw)
                break;
        default:
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("switch case not process\n"));
+                        "switch case not processed\n");
                break;
        }
 
@@ -197,7 +198,7 @@ static bool _rtl_pci_platform_switch_device_pci_aspm(
 }
 
 /*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)
+static void _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value)
 {
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
        struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
@@ -206,8 +207,6 @@ static bool _rtl_pci_switch_clk_req(struct ieee80211_hw *hw, u8 value)
 
        if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
                udelay(100);
-
-       return true;
 }
 
 /*Disable RTL8192SE ASPM & Disable Pci Bridge ASPM*/
@@ -218,7 +217,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;
@@ -232,7 +230,7 @@ static void rtl_pci_disable_aspm(struct ieee80211_hw *hw)
 
        if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
                RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
-                        ("PCI(Bridge) UNKNOWN.\n"));
+                        "PCI(Bridge) UNKNOWN\n");
 
                return;
        }
@@ -254,9 +252,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);
 }
@@ -277,7 +274,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;
@@ -288,13 +284,11 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
 
        if (pcibridge_vendor == PCI_BRIDGE_VENDOR_UNKNOWN) {
                RT_TRACE(rtlpriv, COMP_POWER, DBG_TRACE,
-                        ("PCI(Bridge) UNKNOWN.\n"));
+                        "PCI(Bridge) UNKNOWN\n");
                return;
        }
 
        /*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 |
@@ -303,14 +297,14 @@ 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], "
-                 "DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n",
-                 pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum,
-                 (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
-                 u_pcibridge_aspmsetting));
+                "PlatformEnableASPM():PciBridge busnumber[%x], DevNumbe[%x], funcnumber[%x], Write reg[%x] = %x\n",
+                pcibridge_busnum, pcibridge_devnum, pcibridge_funcnum,
+                (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
+                u_pcibridge_aspmsetting);
 
        udelay(50);
 
@@ -335,25 +329,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;
        }
@@ -364,17 +351,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;
 
        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;
 }
@@ -390,13 +375,12 @@ 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;
 
-       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE,
-                ("Link Control Register =%x\n",
-                 pcipriv->ndis_adapter.linkctrl_reg));
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_TRACE, "Link Control Register =%x\n",
+                pcipriv->ndis_adapter.linkctrl_reg);
 
        pci_read_config_byte(pdev, 0x98, &tmp);
        tmp |= BIT(4);
@@ -488,7 +472,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;
@@ -563,11 +547,10 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
                        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",
-                         ring->idx,
-                         skb_queue_len(&ring->queue),
-                         *(u16 *) (skb->data + 22)));
+                        "new ring->idx:%d, free: skb_queue_len:%d, free: seq:%x\n",
+                        ring->idx,
+                        skb_queue_len(&ring->queue),
+                        *(u16 *) (skb->data + 22));
 
                if (prio == TXCMD_QUEUE) {
                        dev_kfree_skb(skb);
@@ -581,10 +564,10 @@ 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->psc.state_inap = 1;
+                               rtlpriv->mac80211.offchan_delay = true;
+                               rtlpriv->psc.state_inap = true;
                        } else {
-                               rtlpriv->psc.state_inap = 0;
+                               rtlpriv->psc.state_inap = false;
                        }
                }
 
@@ -605,11 +588,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
                                == 2) {
 
                        RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
-                                       ("more desc left, wake"
-                                        "skb_queue@%d,ring->idx = %d,"
-                                        "skb_queue_len = 0x%d\n",
-                                        prio, ring->idx,
-                                        skb_queue_len(&ring->queue)));
+                                "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
@@ -622,10 +603,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);
+               schedule_work(&rtlpriv->works.lps_leave_work);
        }
 }
 
+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);
@@ -637,186 +670,111 @@ 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);
 
-                       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 (stats.crc || stats.hwerror)
+                       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);
-                        */
+               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;
+               }
 
-                       hdr = rtl_get_hdr(skb);
-                       fc = rtl_get_fc(skb);
+               pci_unmap_single(rtlpci->pdev,
+                                *((dma_addr_t *) skb->cb),
+                                rtlpci->rxbuffersize,
+                                PCI_DMA_FROMDEVICE);
 
-                       /* try for new buffer - if allocation fails, drop
-                        * frame and reuse old buffer
-                        */
-                       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;
-                       }
-                       pci_unmap_single(rtlpci->pdev,
-                                        *((dma_addr_t *) skb->cb),
-                                        rtlpci->rxbuffersize,
-                                        PCI_DMA_FROMDEVICE);
+               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 (!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);
-                       }
+               /*
+                * 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);
+                */
 
-                       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);
-                       }
+               _rtl_receive_one(hw, skb, rx_status);
+
+               if (((rtlpriv->link_info.num_rx_inperiod +
+                       rtlpriv->link_info.num_tx_inperiod) > 8) ||
+                       (rtlpriv->link_info.num_rx_inperiod > 2)) {
+                       schedule_work(&rtlpriv->works.lps_leave_work);
+               }
 
-                       skb = new_skb;
+               dev_kfree_skb_any(skb);
+               skb = new_skb;
 
-                       rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci->
-                                                            rx_ring
-                                                            [rx_queue_idx].
-                                                            idx] = skb;
-                       *((dma_addr_t *) skb->cb) =
+               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 = (*((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;
+       irqreturn_t ret = IRQ_HANDLED;
 
        spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
 
@@ -824,44 +782,45 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
        rtlpriv->cfg->ops->interrupt_recognized(hw, &inta, &intb);
 
        /*Shared IRQ or HW disappared */
-       if (!inta || inta == 0xffff)
+       if (!inta || inta == 0xffff) {
+               ret = IRQ_NONE;
                goto done;
+       }
 
        /*<1> beacon related */
        if (inta & rtlpriv->cfg->maps[RTL_IMR_TBDOK]) {
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("beacon ok interrupt!\n"));
+                        "beacon ok interrupt!\n");
        }
 
        if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TBDER])) {
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("beacon err interrupt!\n"));
+                        "beacon err interrupt!\n");
        }
 
        if (inta & rtlpriv->cfg->maps[RTL_IMR_BDOK]) {
-               RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("beacon interrupt!\n"));
+               RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "beacon interrupt!\n");
        }
 
        if (inta & rtlpriv->cfg->maps[RTL_IMR_BcnInt]) {
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("prepare beacon for interrupt!\n"));
+                        "prepare beacon for interrupt!\n");
                tasklet_schedule(&rtlpriv->works.irq_prepare_bcn_tasklet);
        }
 
        /*<3> Tx related */
        if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_TXFOVW]))
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("IMR_TXFOVW!\n"));
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "IMR_TXFOVW!\n");
 
        if (inta & rtlpriv->cfg->maps[RTL_IMR_MGNTDOK]) {
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("Manage ok interrupt!\n"));
+                        "Manage ok interrupt!\n");
                _rtl_pci_tx_isr(hw, MGNT_QUEUE);
        }
 
        if (inta & rtlpriv->cfg->maps[RTL_IMR_HIGHDOK]) {
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("HIGH_QUEUE ok interrupt!\n"));
+                        "HIGH_QUEUE ok interrupt!\n");
                _rtl_pci_tx_isr(hw, HIGH_QUEUE);
        }
 
@@ -869,7 +828,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
                rtlpriv->link_info.num_tx_inperiod++;
 
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("BK Tx OK interrupt!\n"));
+                        "BK Tx OK interrupt!\n");
                _rtl_pci_tx_isr(hw, BK_QUEUE);
        }
 
@@ -877,7 +836,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
                rtlpriv->link_info.num_tx_inperiod++;
 
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("BE TX OK interrupt!\n"));
+                        "BE TX OK interrupt!\n");
                _rtl_pci_tx_isr(hw, BE_QUEUE);
        }
 
@@ -885,7 +844,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
                rtlpriv->link_info.num_tx_inperiod++;
 
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("VI TX OK interrupt!\n"));
+                        "VI TX OK interrupt!\n");
                _rtl_pci_tx_isr(hw, VI_QUEUE);
        }
 
@@ -893,7 +852,7 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
                rtlpriv->link_info.num_tx_inperiod++;
 
                RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                        ("Vo TX OK interrupt!\n"));
+                        "Vo TX OK interrupt!\n");
                _rtl_pci_tx_isr(hw, VO_QUEUE);
        }
 
@@ -902,37 +861,34 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
                        rtlpriv->link_info.num_tx_inperiod++;
 
                        RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
-                                       ("CMD TX OK interrupt!\n"));
+                                "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"));
+               RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE, "Rx ok interrupt!\n");
                _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"));
+                        "rx descriptor unavailable!\n");
                _rtl_pci_rx_interrupt(hw);
        }
 
        if (unlikely(inta & rtlpriv->cfg->maps[RTL_IMR_RXFOVW])) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, ("rx overflow !\n"));
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING, "rx overflow !\n");
                _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;
-
 done:
        spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-       return IRQ_HANDLED;
+       return ret;
 }
 
 static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw)
@@ -956,8 +912,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);
@@ -977,6 +938,15 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
        return;
 }
 
+static void rtl_lps_leave_work_callback(struct work_struct *work)
+{
+       struct rtl_works *rtlworks =
+           container_of(work, struct rtl_works, lps_leave_work);
+       struct ieee80211_hw *hw = rtlworks->hw;
+
+       rtl_lps_leave(hw);
+}
+
 static void _rtl_pci_init_trx_var(struct ieee80211_hw *hw)
 {
        struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw));
@@ -1038,6 +1008,7 @@ 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);
+       INIT_WORK(&rtlpriv->works.lps_leave_work, rtl_lps_leave_work_callback);
 }
 
 static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
@@ -1055,7 +1026,7 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
 
        if (!ring || (unsigned long)ring & 0xFF) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("Cannot allocate TX ring (prio = %d)\n", prio));
+                        "Cannot allocate TX ring (prio = %d)\n", prio);
                return -ENOMEM;
        }
 
@@ -1066,8 +1037,8 @@ static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
        rtlpci->tx_ring[prio].entries = entries;
        skb_queue_head_init(&rtlpci->tx_ring[prio].queue);
 
-       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
-                ("queue:%d, ring_addr:%p\n", prio, ring));
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "queue:%d, ring_addr:%p\n",
+                prio, ring);
 
        for (i = 0; i < entries; i++) {
                nextdescaddress = (u32) dma +
@@ -1105,7 +1076,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
                if (!rtlpci->rx_ring[rx_queue_idx].desc ||
                    (unsigned long)rtlpci->rx_ring[rx_queue_idx].desc & 0xFF) {
                        RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                                ("Cannot allocate RX ring\n"));
+                                "Cannot allocate RX ring\n");
                        return -ENOMEM;
                }
 
@@ -1182,10 +1153,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)
@@ -1209,12 +1182,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;
+               }
        }
 }
 
@@ -1382,7 +1357,7 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
        u8 temp_one = 1;
 
        if (ieee80211_is_auth(fc)) {
-               RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
+               RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, "MAC80211_LINKING\n");
                rtl_ips_nic_on(hw);
        }
 
@@ -1415,10 +1390,9 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
 
        if ((own == 1) && (hw_queue != BEACON_QUEUE)) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-                        ("No more TX desc@%d, ring->idx = %d,"
-                         "idx = %d, skb_queue_len = 0x%d\n",
-                         hw_queue, ring->idx, idx,
-                         skb_queue_len(&ring->queue)));
+                        "No more TX desc@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+                        hw_queue, ring->idx, idx,
+                        skb_queue_len(&ring->queue));
 
                spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
                return skb->len;
@@ -1453,11 +1427,9 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
            hw_queue != BEACON_QUEUE) {
 
                RT_TRACE(rtlpriv, COMP_ERR, DBG_LOUD,
-                        ("less desc left, stop skb_queue@%d, "
-                         "ring->idx = %d,"
-                         "idx = %d, skb_queue_len = 0x%d\n",
-                         hw_queue, ring->idx, idx,
-                         skb_queue_len(&ring->queue)));
+                        "less desc left, stop skb_queue@%d, ring->idx = %d, idx = %d, skb_queue_len = 0x%d\n",
+                        hw_queue, ring->idx, idx,
+                        skb_queue_len(&ring->queue));
 
                ieee80211_stop_queue(hw, skb_get_queue_mapping(skb));
        }
@@ -1507,6 +1479,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw)
 
        synchronize_irq(rtlpci->pdev->irq);
        tasklet_kill(&rtlpriv->works.irq_tasklet);
+       cancel_work_sync(&rtlpriv->works.lps_leave_work);
 
        flush_workqueue(rtlpriv->works.rtl_wq);
        destroy_workqueue(rtlpriv->works.rtl_wq);
@@ -1523,11 +1496,11 @@ static int rtl_pci_init(struct ieee80211_hw *hw, struct pci_dev *pdev)
        err = _rtl_pci_init_trx_ring(hw);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("tx ring initialization failed"));
+                        "tx ring initialization failed\n");
                return err;
        }
 
-       return 1;
+       return 0;
 }
 
 static int rtl_pci_start(struct ieee80211_hw *hw)
@@ -1545,23 +1518,23 @@ static int rtl_pci_start(struct ieee80211_hw *hw)
        err = rtlpriv->cfg->ops->hw_init(hw);
        if (err) {
                RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                        ("Failed to config hardware!\n"));
+                        "Failed to config hardware!\n");
                return err;
        }
 
        rtlpriv->cfg->ops->enable_interrupt(hw);
-       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, ("enable_interrupt OK\n"));
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD, "enable_interrupt OK\n");
 
        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);
 
        rtlpci->up_first_time = false;
 
-       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, ("OK\n"));
+       RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, "OK\n");
        return 0;
 }
 
@@ -1575,12 +1548,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);
+       cancel_work_sync(&rtlpriv->works.lps_leave_work);
 
        spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
        while (ppsc->rfchange_inprogress) {
@@ -1598,6 +1572,9 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
 
        rtlpci->driver_is_goingto_unload = true;
        rtlpriv->cfg->ops->hw_disable(hw);
+       /* some things are not needed if firmware not available */
+       if (!rtlpriv->max_fw_size)
+               return;
        rtlpriv->cfg->ops->led_control(hw, LED_CTL_POWER_OFF);
 
        spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
@@ -1626,6 +1603,16 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
        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 ||
@@ -1637,20 +1624,20 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
                switch (revisionid) {
                case RTL_PCI_REVISION_ID_8192PCIE:
                        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                                ("8192 PCI-E is found - "
-                                 "vid/did=%x/%x\n", venderid, deviceid));
+                                "8192 PCI-E is found - vid/did=%x/%x\n",
+                                venderid, deviceid);
                        rtlhal->hw_type = HARDWARE_TYPE_RTL8192E;
                        break;
                case RTL_PCI_REVISION_ID_8192SE:
                        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                                ("8192SE is found - "
-                                 "vid/did=%x/%x\n", venderid, deviceid));
+                                "8192SE is found - vid/did=%x/%x\n",
+                                venderid, deviceid);
                        rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE;
                        break;
                default:
                        RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-                                ("Err: Unknown device - "
-                                 "vid/did=%x/%x\n", venderid, deviceid));
+                                "Err: Unknown device - vid/did=%x/%x\n",
+                                venderid, deviceid);
                        rtlhal->hw_type = HARDWARE_TYPE_RTL8192SE;
                        break;
 
@@ -1661,18 +1648,18 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
                   deviceid == RTL_PCI_8188CE_DID) {
                rtlhal->hw_type = HARDWARE_TYPE_RTL8192CE;
                RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                        ("8192C PCI-E is found - "
-                         "vid/did=%x/%x\n", venderid, deviceid));
+                        "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));
+                        "8192D PCI-E is found - vid/did=%x/%x\n",
+                        venderid, deviceid);
        } else {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_WARNING,
-                        ("Err: Unknown device -"
-                         " vid/did=%x/%x\n", venderid, deviceid));
+                        "Err: Unknown device - vid/did=%x/%x\n",
+                        venderid, deviceid);
 
                rtlhal->hw_type = RTL_DEFAULT_HARDWARE_TYPE;
        }
@@ -1680,19 +1667,18 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
        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"));
+                               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"));
+                                        "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));
+                                "Unknown device - VendorID/DeviceID=%x/%x, Revision=%x\n",
+                                venderid, deviceid, revisionid);
                        rtlhal->interfaceindex = 0;
                }
        }
@@ -1701,15 +1687,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;
+                       }
                }
        }
 
@@ -1721,10 +1709,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 =
@@ -1740,23 +1724,21 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
        }
 
        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                ("pcidev busnumber:devnumber:funcnumber:"
-                 "vendor:link_ctl %d:%d:%d:%x:%x\n",
-                 pcipriv->ndis_adapter.busnumber,
-                 pcipriv->ndis_adapter.devnumber,
-                 pcipriv->ndis_adapter.funcnumber,
-                 pdev->vendor, pcipriv->ndis_adapter.linkctrl_reg));
+                "pcidev busnumber:devnumber:funcnumber:vendor:link_ctl %d:%d:%d:%x:%x\n",
+                pcipriv->ndis_adapter.busnumber,
+                pcipriv->ndis_adapter.devnumber,
+                pcipriv->ndis_adapter.funcnumber,
+                pdev->vendor, pcipriv->ndis_adapter.linkctrl_reg);
 
        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                ("pci_bridge busnumber:devnumber:funcnumber:vendor:"
-                 "pcie_cap:link_ctl_reg:amd %d:%d:%d:%x:%x:%x:%x\n",
-                 pcipriv->ndis_adapter.pcibridge_busnum,
-                 pcipriv->ndis_adapter.pcibridge_devnum,
-                 pcipriv->ndis_adapter.pcibridge_funcnum,
-                 pcibridge_vendors[pcipriv->ndis_adapter.pcibridge_vendor],
-                 pcipriv->ndis_adapter.pcibridge_pciehdr_offset,
-                 pcipriv->ndis_adapter.pcibridge_linkctrlreg,
-                 pcipriv->ndis_adapter.amd_l1_patch));
+                "pci_bridge busnumber:devnumber:funcnumber:vendor:pcie_cap:link_ctl_reg:amd %d:%d:%d:%x:%x:%x:%x\n",
+                pcipriv->ndis_adapter.pcibridge_busnum,
+                pcipriv->ndis_adapter.pcibridge_devnum,
+                pcipriv->ndis_adapter.pcibridge_funcnum,
+                pcibridge_vendors[pcipriv->ndis_adapter.pcibridge_vendor],
+                pcipriv->ndis_adapter.pcibridge_pciehdr_offset,
+                pcipriv->ndis_adapter.pcibridge_linkctrlreg,
+                pcipriv->ndis_adapter.amd_l1_patch);
 
        rtl_pci_parse_configuration(pdev, hw);
 
@@ -1776,18 +1758,17 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
 
        err = pci_enable_device(pdev);
        if (err) {
-               RT_ASSERT(false,
-                         ("%s : Cannot enable new PCI device\n",
-                          pci_name(pdev)));
+               RT_ASSERT(false, "%s : Cannot enable new PCI device\n",
+                         pci_name(pdev));
                return err;
        }
 
        if (!pci_set_dma_mask(pdev, DMA_BIT_MASK(32))) {
                if (pci_set_consistent_dma_mask(pdev, DMA_BIT_MASK(32))) {
-                       RT_ASSERT(false, ("Unable to obtain 32bit DMA "
-                                         "for consistent allocations\n"));
-                       pci_disable_device(pdev);
-                       return -ENOMEM;
+                       RT_ASSERT(false,
+                                 "Unable to obtain 32bit DMA for consistent allocations\n");
+                       err = -ENOMEM;
+                       goto fail1;
                }
        }
 
@@ -1797,7 +1778,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
                                sizeof(struct rtl_priv), &rtl_ops);
        if (!hw) {
                RT_ASSERT(false,
-                         ("%s : ieee80211 alloc failed\n", pci_name(pdev)));
+                         "%s : ieee80211 alloc failed\n", pci_name(pdev));
                err = -ENOMEM;
                goto fail1;
        }
@@ -1808,6 +1789,7 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
        rtlpriv = hw->priv;
        pcipriv = (void *)rtlpriv->priv;
        pcipriv->dev.pdev = pdev;
+       init_completion(&rtlpriv->firmware_loading_complete);
 
        /* init cfg & intf_ops */
        rtlpriv->rtlhal.interface = INTF_PCI;
@@ -1827,8 +1809,8 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
        /* MEM map */
        err = pci_request_regions(pdev, KBUILD_MODNAME);
        if (err) {
-               RT_ASSERT(false, ("Can't obtain PCI resources\n"));
-               return err;
+               RT_ASSERT(false, "Can't obtain PCI resources\n");
+               goto fail1;
        }
 
        pmem_start = pci_resource_start(pdev, rtlpriv->cfg->bar_id);
@@ -1840,15 +1822,15 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
                        (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"));
+               RT_ASSERT(false, "Can't map PCI mem\n");
+               err = -ENOMEM;
                goto fail2;
        }
 
        RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                ("mem mapped space: start: 0x%08lx len:%08lx "
-                 "flags:%08lx, after map:0x%08lx\n",
-                 pmem_start, pmem_len, pmem_flags,
-                 rtlpriv->io.pci_mem_start));
+                "mem mapped space: start: 0x%08lx len:%08lx flags:%08lx, after map:0x%08lx\n",
+                pmem_start, pmem_len, pmem_flags,
+                rtlpriv->io.pci_mem_start);
 
        /* Disable Clk Request */
        pci_write_config_byte(pdev, 0x81, 0);
@@ -1858,7 +1840,10 @@ 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)) {
+               err = -ENODEV;
+               goto fail3;
+       }
 
        /* Init IO handler */
        _rtl_pci_io_handler_init(&pdev->dev, hw);
@@ -1866,14 +1851,6 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
        /*like read eeprom and so on */
        rtlpriv->cfg->ops->read_eeprom_info(hw);
 
-       if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("Can't init_sw_vars.\n"));
-               goto fail3;
-       }
-
-       rtlpriv->cfg->ops->init_sw_leds(hw);
-
        /*aspm */
        rtl_pci_init_aspm(hw);
 
@@ -1881,69 +1858,63 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
        err = rtl_init_core(hw);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("Can't allocate sw for mac80211.\n"));
+                        "Can't allocate sw for mac80211\n");
                goto fail3;
        }
 
        /* Init PCI sw */
-       err = !rtl_pci_init(hw, pdev);
+       err = rtl_pci_init(hw, pdev);
        if (err) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("Failed to init PCI.\n"));
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Failed to init PCI\n");
                goto fail3;
        }
 
-       err = ieee80211_register_hw(hw);
-       if (err) {
-               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("Can't register mac80211 hw.\n"));
+       if (rtlpriv->cfg->ops->init_sw_vars(hw)) {
+               RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG, "Can't init_sw_vars\n");
+               err = -ENODEV;
                goto fail3;
-       } else {
-               rtlpriv->mac80211.mac80211_registered = 1;
        }
 
+       rtlpriv->cfg->ops->init_sw_leds(hw);
+
        err = sysfs_create_group(&pdev->dev.kobj, &rtl_attribute_group);
        if (err) {
                RT_TRACE(rtlpriv, COMP_ERR, DBG_EMERG,
-                        ("failed to create sysfs device attributes\n"));
+                        "failed to create sysfs device attributes\n");
                goto fail3;
        }
 
-       /*init rfkill */
-       rtl_init_rfkill(hw);
-
        rtlpci = rtl_pcidev(pcipriv);
        err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
                          IRQF_SHARED, KBUILD_MODNAME, hw);
        if (err) {
                RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
-                        ("%s: failed to register IRQ handler\n",
-                         wiphy_name(hw->wiphy)));
+                        "%s: failed to register IRQ handler\n",
+                        wiphy_name(hw->wiphy));
                goto fail3;
-       } else {
-               rtlpci->irq_alloc = 1;
        }
+       rtlpci->irq_alloc = 1;
 
-       set_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
        return 0;
 
 fail3:
-       pci_set_drvdata(pdev, NULL);
        rtl_deinit_core(hw);
        _rtl_pci_io_handler_release(hw);
-       ieee80211_free_hw(hw);
 
        if (rtlpriv->io.pci_mem_start != 0)
                pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
 
 fail2:
        pci_release_regions(pdev);
+       complete(&rtlpriv->firmware_loading_complete);
 
 fail1:
-
+       if (hw)
+               ieee80211_free_hw(hw);
+       pci_set_drvdata(pdev, NULL);
        pci_disable_device(pdev);
 
-       return -ENODEV;
+       return err;
 
 }
 EXPORT_SYMBOL(rtl_pci_probe);
@@ -1956,6 +1927,8 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
        struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
        struct rtl_mac *rtlmac = rtl_mac(rtlpriv);
 
+       /* just in case driver is removed before firmware callback */
+       wait_for_completion(&rtlpriv->firmware_loading_complete);
        clear_bit(RTL_STATUS_INTERFACE_START, &rtlpriv->status);
 
        sysfs_remove_group(&pdev->dev.kobj, &rtl_attribute_group);
@@ -1968,6 +1941,7 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
                rtl_deinit_deferred_work(hw);
                rtlpriv->intf_ops->adapter_stop(hw);
        }
+       rtlpriv->cfg->ops->disable_interrupt(hw);
 
        /*deinit rfkill */
        rtl_deinit_rfkill(hw);
@@ -2012,36 +1986,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;