aboutsummaryrefslogtreecommitdiff
path: root/drivers/net/wireless/rtlwifi/pci.c
diff options
context:
space:
mode:
Diffstat (limited to 'drivers/net/wireless/rtlwifi/pci.c')
-rw-r--r--drivers/net/wireless/rtlwifi/pci.c661
1 files changed, 411 insertions, 250 deletions
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c
index 9245d882c06..dae55257f0e 100644
--- a/drivers/net/wireless/rtlwifi/pci.c
+++ b/drivers/net/wireless/rtlwifi/pci.c
@@ -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
@@ -27,13 +27,21 @@
*
*****************************************************************************/
-#include <linux/export.h>
-#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>
+#include <linux/kmemleak.h>
+#include <linux/module.h>
+
+MODULE_AUTHOR("lizhaoming <chaoming_li@realsil.com.cn>");
+MODULE_AUTHOR("Realtek WlanFAE <wlanfae@realtek.com>");
+MODULE_AUTHOR("Larry Finger <Larry.FInger@lwfinger.net>");
+MODULE_LICENSE("GPL");
+MODULE_DESCRIPTION("PCI basic driver for rtlwifi");
static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = {
PCI_VENDOR_ID_INTEL,
@@ -58,7 +66,7 @@ static u8 _rtl_mac_to_hwqueue(struct ieee80211_hw *hw,
if (unlikely(ieee80211_is_beacon(fc)))
return BEACON_QUEUE;
- if (ieee80211_is_mgmt(fc))
+ if (ieee80211_is_mgmt(fc) || ieee80211_is_ctl(fc))
return MGNT_QUEUE;
if (rtlhal->hw_type == HARDWARE_TYPE_RTL8192SE)
if (ieee80211_is_nullfunc(fc))
@@ -170,7 +178,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;
}
@@ -198,7 +206,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));
@@ -207,8 +215,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*/
@@ -232,7 +238,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;
}
@@ -272,9 +278,6 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_ps_ctl *ppsc = rtl_psc(rtl_priv(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;
u8 pcibridge_vendor = pcipriv->ndis_adapter.pcibridge_vendor;
u8 num4bytes = pcipriv->ndis_adapter.num4bytes;
u16 aspmlevel;
@@ -286,7 +289,7 @@ 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;
}
@@ -303,11 +306,9 @@ static void rtl_pci_enable_aspm(struct ieee80211_hw *hw)
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(): Write reg[%x] = %x\n",
+ (pcipriv->ndis_adapter.pcibridge_pciehdr_offset + 0x10),
+ u_pcibridge_aspmsetting);
udelay(50);
@@ -351,6 +352,49 @@ static bool rtl_pci_get_amd_l1_patch(struct ieee80211_hw *hw)
return status;
}
+static bool rtl_pci_check_buddy_priv(struct ieee80211_hw *hw,
+ struct rtl_priv **buddy_priv)
+{
+ struct rtl_priv *rtlpriv = rtl_priv(hw);
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ bool find_buddy_priv = false;
+ struct rtl_priv *tpriv = NULL;
+ struct rtl_pci_priv *tpcipriv = NULL;
+
+ if (!list_empty(&rtlpriv->glb_var->glb_priv_list)) {
+ list_for_each_entry(tpriv, &rtlpriv->glb_var->glb_priv_list,
+ list) {
+ if (tpriv) {
+ tpcipriv = (struct rtl_pci_priv *)tpriv->priv;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "pcipriv->ndis_adapter.funcnumber %x\n",
+ pcipriv->ndis_adapter.funcnumber);
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "tpcipriv->ndis_adapter.funcnumber %x\n",
+ tpcipriv->ndis_adapter.funcnumber);
+
+ if ((pcipriv->ndis_adapter.busnumber ==
+ tpcipriv->ndis_adapter.busnumber) &&
+ (pcipriv->ndis_adapter.devnumber ==
+ tpcipriv->ndis_adapter.devnumber) &&
+ (pcipriv->ndis_adapter.funcnumber !=
+ tpcipriv->ndis_adapter.funcnumber)) {
+ find_buddy_priv = true;
+ break;
+ }
+ }
+ }
+ }
+
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "find_buddy_priv %d\n", find_buddy_priv);
+
+ if (find_buddy_priv)
+ *buddy_priv = tpriv;
+
+ return find_buddy_priv;
+}
+
static void rtl_pci_get_linkcontrol_field(struct ieee80211_hw *hw)
{
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
@@ -374,17 +418,14 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev,
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
u8 tmp;
- int pos;
- u8 linkctrl_reg;
+ u16 linkctrl_reg;
/*Link Control Register */
- pos = pci_pcie_cap(pdev);
- pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg);
- pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg;
+ pcie_capability_read_word(pdev, PCI_EXP_LNKCTL, &linkctrl_reg);
+ pcipriv->ndis_adapter.linkctrl_reg = (u8)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);
@@ -425,17 +466,14 @@ static void _rtl_pci_io_handler_init(struct device *dev,
}
-static void _rtl_pci_io_handler_release(struct ieee80211_hw *hw)
-{
-}
-
static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
struct sk_buff *skb, struct rtl_tcb_desc *tcb_desc, u8 tid)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- u8 additionlen = FCS_LEN;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
struct sk_buff *next_skb;
+ u8 additionlen = FCS_LEN;
/* here open is 4, wep/tkip is 8, aes is 12*/
if (info->control.hw_key)
@@ -460,7 +498,7 @@ static bool _rtl_update_earlymode_info(struct ieee80211_hw *hw,
next_skb))
break;
- if (tcb_desc->empkt_num >= 5)
+ if (tcb_desc->empkt_num >= rtlhal->max_earlymode_num)
break;
}
spin_unlock_bh(&rtlpriv->locks.waitq_lock);
@@ -476,14 +514,20 @@ 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;
+ struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
int tid;
if (!rtlpriv->rtlhal.earlymode_enable)
return;
+ if (rtlpriv->dm.supp_phymode_switch &&
+ (rtlpriv->easy_concurrent_ctl.switch_in_process ||
+ (rtlpriv->buddy_priv &&
+ rtlpriv->buddy_priv->easy_concurrent_ctl.switch_in_process)))
+ return;
/* we juse use em for BE/BK/VI/VO */
for (tid = 7; tid >= 0; tid--) {
- u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(hw, tid)];
+ u8 hw_queue = ac_to_hwq[rtl_tid_to_ac(tid)];
struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[hw_queue];
while (!mac->act_scanning &&
rtlpriv->psc.rfpwr_state == ERFON) {
@@ -492,7 +536,8 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
spin_lock_bh(&rtlpriv->locks.waitq_lock);
if (!skb_queue_empty(&mac->skb_waitq[tid]) &&
- (ring->entries - skb_queue_len(&ring->queue) > 5)) {
+ (ring->entries - skb_queue_len(&ring->queue) >
+ rtlhal->max_earlymode_num)) {
skb = skb_dequeue(&mac->skb_waitq[tid]);
} else {
spin_unlock_bh(&rtlpriv->locks.waitq_lock);
@@ -507,7 +552,7 @@ static void _rtl_pci_tx_chk_waitq(struct ieee80211_hw *hw)
_rtl_update_earlymode_info(hw, skb,
&tcb_desc, tid);
- rtlpriv->intf_ops->adapter_tx(hw, skb, &tcb_desc);
+ rtlpriv->intf_ops->adapter_tx(hw, NULL, skb, &tcb_desc);
}
}
}
@@ -530,9 +575,8 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
u8 own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) entry, true,
HW_DESC_OWN);
- /*
- *beacon packet will only use the first
- *descriptor defautly,and the own may not
+ /*beacon packet will only use the first
+ *descriptor by defaut, and the own may not
*be cleared by the hardware
*/
if (own)
@@ -551,11 +595,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);
@@ -564,8 +607,9 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
}
/* for sw LPS, just after NULL skb send out, we can
- * sure AP kown we are sleeped, our we should not let
- * rf to sleep*/
+ * sure AP knows we are sleeping, we should not let
+ * rf sleep
+ */
fc = rtl_get_fc(skb);
if (ieee80211_is_nullfunc(fc)) {
if (ieee80211_has_pm(fc)) {
@@ -575,6 +619,15 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio)
rtlpriv->psc.state_inap = false;
}
}
+ if (ieee80211_is_action(fc)) {
+ struct ieee80211_mgmt *action_frame =
+ (struct ieee80211_mgmt *)skb->data;
+ if (action_frame->u.action.u.ht_smps.action ==
+ WLAN_HT_ACTION_SMPS) {
+ dev_kfree_skb(skb);
+ goto tx_status_ok;
+ }
+ }
/* update tid tx pkt num */
tid = rtl_get_tid(skb);
@@ -593,11 +646,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
@@ -610,7 +661,8 @@ tx_status_ok:
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);
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
}
}
@@ -636,8 +688,6 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
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);
@@ -645,6 +695,10 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
rtlpriv->link_info.num_rx_inperiod++;
}
+ /* static bcn for roaming */
+ rtl_beacon_statistic(hw, skb);
+ rtl_p2p_info(hw, (void *)skb->data, skb->len);
+
/* for sw lps */
rtl_swlps_beacon(hw, (void *)skb->data, skb->len);
rtl_recognize_peer(hw, (void *)skb->data, skb->len);
@@ -657,6 +711,8 @@ static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb,
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);
@@ -678,11 +734,12 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
struct rtl_stats stats = {
.signal = 0,
- .noise = -98,
.rate = 0,
};
int index = rtlpci->rx_ring[rx_queue_idx].idx;
+ if (rtlpci->driver_is_goingto_unload)
+ return;
/*RX NORMAL PKT */
while (count--) {
/*rx descriptor */
@@ -709,11 +766,11 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
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"));
+ RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), DBG_DMESG,
+ "can't alloc skb for rx\n");
goto done;
}
+ kmemleak_not_leak(new_skb);
pci_unmap_single(rtlpci->pdev,
*((dma_addr_t *) skb->cb),
@@ -734,9 +791,10 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *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);
+ rtlpriv->link_info.num_tx_inperiod) > 8) ||
+ (rtlpriv->link_info.num_rx_inperiod > 2)) {
+ rtlpriv->enter_ps = false;
+ schedule_work(&rtlpriv->works.lps_change_work);
}
dev_kfree_skb_any(skb);
@@ -750,21 +808,23 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw)
done:
bufferaddress = (*((dma_addr_t *)skb->cb));
+ if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress))
+ return;
tmp_one = 1;
- rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
HW_DESC_RXBUFF_ADDR,
(u8 *)&bufferaddress);
- rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
HW_DESC_RXPKT_LEN,
(u8 *)&rtlpci->rxbuffersize);
if (index == rtlpci->rxringcount - 1)
- rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false,
HW_DESC_RXERO,
- (u8 *)&tmp_one);
+ &tmp_one);
- rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN,
- (u8 *)&tmp_one);
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, false, HW_DESC_RXOWN,
+ &tmp_one);
index = (index + 1) % rtlpci->rxringcount;
}
@@ -796,38 +856,37 @@ static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id)
/*<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]) {
+ 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);
}
@@ -835,7 +894,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);
}
@@ -843,7 +902,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);
}
@@ -851,7 +910,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);
}
@@ -859,7 +918,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);
}
@@ -868,28 +927,38 @@ 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);
}
+ /*fw related*/
+ if (rtlhal->hw_type == HARDWARE_TYPE_RTL8723AE) {
+ if (inta & rtlpriv->cfg->maps[RTL_IMR_C2HCMD]) {
+ RT_TRACE(rtlpriv, COMP_INTR, DBG_TRACE,
+ "firmware interrupt!\n");
+ queue_delayed_work(rtlpriv->works.rtl_wq,
+ &rtlpriv->works.fwevt_wq, 0);
+ }
+ }
+
if (rtlpriv->rtlhal.earlymode_enable)
tasklet_schedule(&rtlpriv->works.irq_tasklet);
@@ -914,13 +983,20 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
struct sk_buff *pskb = NULL;
struct rtl_tx_desc *pdesc = NULL;
struct rtl_tcb_desc tcb_desc;
+ /*This is for new trx flow*/
+ struct rtl_tx_buffer_desc *pbuffer_desc = NULL;
u8 temp_one = 1;
memset(&tcb_desc, 0, sizeof(struct rtl_tcb_desc));
ring = &rtlpci->tx_ring[BEACON_QUEUE];
pskb = __skb_dequeue(&ring->queue);
- if (pskb)
+ if (pskb) {
+ struct rtl_tx_desc *entry = &ring->desc[ring->idx];
+ pci_unmap_single(rtlpci->pdev, rtlpriv->cfg->ops->get_desc(
+ (u8 *) entry, true, HW_DESC_TXBUFF_ADDR),
+ pskb->len, PCI_DMA_TODEVICE);
kfree_skb(pskb);
+ }
/*NB: the beacon data buffer must be 32-bit aligned. */
pskb = ieee80211_beacon_get(hw, mac->vif);
@@ -930,25 +1006,17 @@ static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw)
info = IEEE80211_SKB_CB(pskb);
pdesc = &ring->desc[0];
rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *) pdesc,
- info, pskb, BEACON_QUEUE, &tcb_desc);
+ (u8 *)pbuffer_desc, info, NULL, pskb,
+ BEACON_QUEUE, &tcb_desc);
__skb_queue_tail(&ring->queue, pskb);
- rtlpriv->cfg->ops->set_desc((u8 *) pdesc, true, HW_DESC_OWN,
- (u8 *)&temp_one);
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true, HW_DESC_OWN,
+ &temp_one);
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));
@@ -1001,7 +1069,7 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw,
mac->current_ampdu_factor = 3;
/*QOS*/
- rtlpci->acm_method = eAcmWay2_SW;
+ rtlpci->acm_method = EACMWAY2_SW;
/*task */
tasklet_init(&rtlpriv->works.irq_tasklet,
@@ -1010,7 +1078,8 @@ 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);
+ INIT_WORK(&rtlpriv->works.lps_change_work,
+ rtl_lps_change_work_callback);
}
static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw,
@@ -1028,7 +1097,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;
}
@@ -1039,15 +1108,15 @@ 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 +
((i + 1) % entries) *
sizeof(*ring);
- rtlpriv->cfg->ops->set_desc((u8 *)&(ring[i]),
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)&(ring[i]),
true, HW_DESC_TX_NEXTDESC_ADDR,
(u8 *)&nextdescaddress);
}
@@ -1078,7 +1147,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;
}
@@ -1101,6 +1170,7 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
u32 bufferaddress;
if (!skb)
return 0;
+ kmemleak_not_leak(skb);
entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
/*skb->dev = dev; */
@@ -1117,20 +1187,24 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw)
PCI_DMA_FROMDEVICE);
bufferaddress = (*((dma_addr_t *)skb->cb));
- rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
+ if (pci_dma_mapping_error(rtlpci->pdev, bufferaddress)) {
+ dev_kfree_skb_any(skb);
+ return 1;
+ }
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
HW_DESC_RXBUFF_ADDR,
(u8 *)&bufferaddress);
- rtlpriv->cfg->ops->set_desc((u8 *)entry, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
HW_DESC_RXPKT_LEN,
(u8 *)&rtlpci->
rxbuffersize);
- rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
HW_DESC_RXOWN,
- (u8 *)&tmp_one);
+ &tmp_one);
}
- rtlpriv->cfg->ops->set_desc((u8 *) entry, false,
- HW_DESC_RXERO, (u8 *)&tmp_one);
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry, false,
+ HW_DESC_RXERO, &tmp_one);
}
return 0;
}
@@ -1155,10 +1229,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)
@@ -1182,12 +1258,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;
+ }
}
}
@@ -1256,10 +1334,10 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
for (i = 0; i < rtlpci->rxringcount; i++) {
entry = &rtlpci->rx_ring[rx_queue_idx].desc[i];
- rtlpriv->cfg->ops->set_desc((u8 *) entry,
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)entry,
false,
HW_DESC_RXOWN,
- (u8 *)&tmp_one);
+ &tmp_one);
}
rtlpci->rx_ring[rx_queue_idx].idx = 0;
}
@@ -1269,17 +1347,18 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
*after reset, release previous pending packet,
*and force the tx idx to the first one
*/
- spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags);
for (i = 0; i < RTL_PCI_MAX_TX_QUEUE_COUNT; i++) {
if (rtlpci->tx_ring[i].desc) {
struct rtl8192_tx_ring *ring = &rtlpci->tx_ring[i];
while (skb_queue_len(&ring->queue)) {
- struct rtl_tx_desc *entry =
- &ring->desc[ring->idx];
- struct sk_buff *skb =
- __skb_dequeue(&ring->queue);
+ struct rtl_tx_desc *entry;
+ struct sk_buff *skb;
+ spin_lock_irqsave(&rtlpriv->locks.irq_th_lock,
+ flags);
+ entry = &ring->desc[ring->idx];
+ skb = __skb_dequeue(&ring->queue);
pci_unmap_single(rtlpci->pdev,
rtlpriv->cfg->ops->
get_desc((u8 *)
@@ -1287,26 +1366,26 @@ int rtl_pci_reset_trx_ring(struct ieee80211_hw *hw)
true,
HW_DESC_TXBUFF_ADDR),
skb->len, PCI_DMA_TODEVICE);
- kfree_skb(skb);
ring->idx = (ring->idx + 1) % ring->entries;
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+ flags);
+ kfree_skb(skb);
}
ring->idx = 0;
}
}
- spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
-
return 0;
}
static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
struct sk_buff *skb)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
- struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_sta *sta = info->control.sta;
struct rtl_sta_info *sta_entry = NULL;
u8 tid = rtl_get_tid(skb);
+ __le16 fc = rtl_get_fc(skb);
if (!sta)
return false;
@@ -1314,6 +1393,12 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
if (!rtlpriv->rtlhal.earlymode_enable)
return false;
+ if (ieee80211_is_nullfunc(fc))
+ return false;
+ if (ieee80211_is_qos_nullfunc(fc))
+ return false;
+ if (ieee80211_is_pspoll(fc))
+ return false;
if (sta_entry->tids[tid].agg.agg_state != RTL_AGG_OPERATIONAL)
return false;
if (_rtl_mac_to_hwqueue(hw, skb) > VO_QUEUE)
@@ -1332,15 +1417,17 @@ static bool rtl_pci_tx_chk_waitq_insert(struct ieee80211_hw *hw,
return true;
}
-static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
- struct rtl_tcb_desc *ptcb_desc)
+static int rtl_pci_tx(struct ieee80211_hw *hw,
+ struct ieee80211_sta *sta,
+ struct sk_buff *skb,
+ struct rtl_tcb_desc *ptcb_desc)
{
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_sta_info *sta_entry = NULL;
struct ieee80211_tx_info *info = IEEE80211_SKB_CB(skb);
- struct ieee80211_sta *sta = info->control.sta;
struct rtl8192_tx_ring *ring;
struct rtl_tx_desc *pdesc;
+ struct rtl_tx_buffer_desc *ptx_bd_desc = NULL;
u8 idx;
u8 hw_queue = _rtl_mac_to_hwqueue(hw, skb);
unsigned long flags;
@@ -1354,10 +1441,8 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
u8 own;
u8 temp_one = 1;
- if (ieee80211_is_auth(fc)) {
- RT_TRACE(rtlpriv, COMP_SEND, DBG_DMESG, ("MAC80211_LINKING\n"));
- rtl_ips_nic_on(hw);
- }
+ if (ieee80211_is_mgmt(fc))
+ rtl_tx_mgmt_proc(hw, skb);
if (rtlpriv->psc.sw_ps_enabled) {
if (ieee80211_is_data(fc) && !ieee80211_is_nullfunc(fc) &&
@@ -1383,18 +1468,22 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
idx = 0;
pdesc = &ring->desc[idx];
- own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc,
- true, HW_DESC_OWN);
+ if (rtlpriv->use_new_trx_flow) {
+ ptx_bd_desc = &ring->buffer_desc[idx];
+ } else {
+ own = (u8) rtlpriv->cfg->ops->get_desc((u8 *)pdesc,
+ true, HW_DESC_OWN);
- 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)));
+ 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));
- spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock, flags);
- return skb->len;
+ spin_unlock_irqrestore(&rtlpriv->locks.irq_th_lock,
+ flags);
+ return skb->len;
+ }
}
if (ieee80211_is_data_qos(fc)) {
@@ -1414,23 +1503,24 @@ static int rtl_pci_tx(struct ieee80211_hw *hw, struct sk_buff *skb,
rtlpriv->cfg->ops->led_control(hw, LED_CTL_TX);
rtlpriv->cfg->ops->fill_tx_desc(hw, hdr, (u8 *)pdesc,
- info, skb, hw_queue, ptcb_desc);
+ (u8 *)ptx_bd_desc, info, sta, skb, hw_queue, ptcb_desc);
__skb_queue_tail(&ring->queue, skb);
- rtlpriv->cfg->ops->set_desc((u8 *)pdesc, true,
- HW_DESC_OWN, (u8 *)&temp_one);
-
+ if (rtlpriv->use_new_trx_flow) {
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
+ HW_DESC_OWN, &hw_queue);
+ } else {
+ rtlpriv->cfg->ops->set_desc(hw, (u8 *)pdesc, true,
+ HW_DESC_OWN, &temp_one);
+ }
if ((ring->entries - skb_queue_len(&ring->queue)) < 2 &&
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));
}
@@ -1447,10 +1537,14 @@ static void rtl_pci_flush(struct ieee80211_hw *hw, bool drop)
struct rtl_priv *rtlpriv = rtl_priv(hw);
struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw));
+ struct rtl_mac *mac = rtl_mac(rtl_priv(hw));
u16 i = 0;
int queue_id;
struct rtl8192_tx_ring *ring;
+ if (mac->skip_scan)
+ return;
+
for (queue_id = RTL_PCI_MAX_TX_QUEUE_COUNT - 1; queue_id >= 0;) {
u32 queue_len;
ring = &pcipriv->dev.tx_ring[queue_id];
@@ -1480,7 +1574,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);
+ cancel_work_sync(&rtlpriv->works.lps_change_work);
flush_workqueue(rtlpriv->works.rtl_wq);
destroy_workqueue(rtlpriv->works.rtl_wq);
@@ -1497,7 +1591,7 @@ 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;
}
@@ -1519,12 +1613,12 @@ 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);
@@ -1535,7 +1629,7 @@ static int rtl_pci_start(struct ieee80211_hw *hw)
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;
}
@@ -1554,8 +1648,9 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
*/
set_hal_stop(rtlhal);
+ rtlpci->driver_is_goingto_unload = true;
rtlpriv->cfg->ops->disable_interrupt(hw);
- cancel_work_sync(&rtlpriv->works.lps_leave_work);
+ cancel_work_sync(&rtlpriv->works.lps_change_work);
spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags);
while (ppsc->rfchange_inprogress) {
@@ -1571,8 +1666,10 @@ static void rtl_pci_stop(struct ieee80211_hw *hw)
ppsc->rfchange_inprogress = true;
spin_unlock_irqrestore(&rtlpriv->locks.rf_ps_lock, flags);
- 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);
@@ -1622,42 +1719,51 @@ 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;
+ return false;
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;
}
+ } else if (deviceid == RTL_PCI_8723AE_DID) {
+ rtlhal->hw_type = HARDWARE_TYPE_RTL8723AE;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
+ "8723AE PCI-E is found - "
+ "vid/did=%x/%x\n", venderid, deviceid);
} else if (deviceid == RTL_PCI_8192CET_DID ||
deviceid == RTL_PCI_8192CE_DID ||
deviceid == RTL_PCI_8191CE_DID ||
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 if (deviceid == RTL_PCI_8188EE_DID) {
+ rtlhal->hw_type = HARDWARE_TYPE_RTL8188EE;
+ RT_TRACE(rtlpriv, COMP_INIT, DBG_LOUD,
+ "Find adapter, Hardware type is 8188EE\n");
} 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;
}
@@ -1665,19 +1771,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;
}
}
@@ -1686,6 +1791,9 @@ 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);
+ /* some ARM have no bridge_pdev and will crash here
+ * so we should check if bridge_pdev is NULL
+ */
if (bridge_pdev) {
/*find bridge info if available */
pcipriv->ndis_adapter.pcibridge_vendorid = bridge_pdev->vendor;
@@ -1693,8 +1801,8 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
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));
+ "Pci Bridge Vendor is found index: %d\n",
+ tmp);
break;
}
}
@@ -1723,30 +1831,88 @@ 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);
+ list_add_tail(&rtlpriv->list, &rtlpriv->glb_var->glb_priv_list);
return true;
}
-int __devinit rtl_pci_probe(struct pci_dev *pdev,
+static int rtl_pci_intr_mode_msi(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(pcipriv);
+ int ret;
+
+ ret = pci_enable_msi(rtlpci->pdev);
+ if (ret < 0)
+ return ret;
+
+ ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, hw);
+ if (ret < 0) {
+ pci_disable_msi(rtlpci->pdev);
+ return ret;
+ }
+
+ rtlpci->using_msi = true;
+
+ RT_TRACE(rtlpriv, COMP_INIT|COMP_INTR, DBG_DMESG,
+ "MSI Interrupt Mode!\n");
+ return 0;
+}
+
+static int rtl_pci_intr_mode_legacy(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(pcipriv);
+ int ret;
+
+ ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt,
+ IRQF_SHARED, KBUILD_MODNAME, hw);
+ if (ret < 0)
+ return ret;
+
+ rtlpci->using_msi = false;
+ RT_TRACE(rtlpriv, COMP_INIT|COMP_INTR, DBG_DMESG,
+ "Pin-based Interrupt Mode!\n");
+ return 0;
+}
+
+static int rtl_pci_intr_mode_decide(struct ieee80211_hw *hw)
+{
+ struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw);
+ struct rtl_pci *rtlpci = rtl_pcidev(pcipriv);
+ int ret;
+
+ if (rtlpci->msi_support) {
+ ret = rtl_pci_intr_mode_msi(hw);
+ if (ret < 0)
+ ret = rtl_pci_intr_mode_legacy(hw);
+ } else {
+ ret = rtl_pci_intr_mode_legacy(hw);
+ }
+ return ret;
+}
+
+int rtl_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id)
{
struct ieee80211_hw *hw = NULL;
@@ -1759,18 +1925,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;
}
}
@@ -1780,7 +1945,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;
}
@@ -1789,13 +1954,16 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
pci_set_drvdata(pdev, hw);
rtlpriv = hw->priv;
+ rtlpriv->hw = hw;
pcipriv = (void *)rtlpriv->priv;
pcipriv->dev.pdev = pdev;
+ init_completion(&rtlpriv->firmware_loading_complete);
/* init cfg & intf_ops */
rtlpriv->rtlhal.interface = INTF_PCI;
rtlpriv->cfg = (struct rtl_hal_cfg *)(id->driver_data);
rtlpriv->intf_ops = &rtl_pci_ops;
+ rtlpriv->glb_var = &rtl_global_var;
/*
*init dbgp flags before all
@@ -1810,8 +1978,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);
@@ -1823,15 +1991,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);
@@ -1841,8 +2009,10 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev,
pci_write_config_byte(pdev, 0x04, 0x07);
/* find adapter */
- if (!_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);
@@ -1850,14 +2020,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);
@@ -1865,69 +2027,60 @@ 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);
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);
+ err = rtl_pci_intr_mode_decide(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_disable_device(pdev);
- return -ENODEV;
+ return err;
}
EXPORT_SYMBOL(rtl_pci_probe);
@@ -1940,6 +2093,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);
@@ -1952,20 +2107,25 @@ 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);
rtl_pci_deinit(hw);
rtl_deinit_core(hw);
- _rtl_pci_io_handler_release(hw);
rtlpriv->cfg->ops->deinit_sw_vars(hw);
if (rtlpci->irq_alloc) {
+ synchronize_irq(rtlpci->pdev->irq);
free_irq(rtlpci->pdev->irq, hw);
rtlpci->irq_alloc = 0;
}
+ if (rtlpci->using_msi)
+ pci_disable_msi(rtlpci->pdev);
+
+ list_del(&rtlpriv->list);
if (rtlpriv->io.pci_mem_start != 0) {
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
pci_release_regions(pdev);
@@ -1975,12 +2135,11 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
rtl_pci_disable_aspm(hw);
- pci_set_drvdata(pdev, NULL);
-
ieee80211_free_hw(hw);
}
EXPORT_SYMBOL(rtl_pci_disconnect);
+#ifdef CONFIG_PM_SLEEP
/***************************************
kernel pci power state define:
PCI_D0 ((pci_power_t __force) 0)
@@ -2020,11 +2179,13 @@ int rtl_pci_resume(struct device *dev)
return 0;
}
EXPORT_SYMBOL(rtl_pci_resume);
+#endif /* CONFIG_PM_SLEEP */
struct rtl_intf_ops rtl_pci_ops = {
.read_efuse_byte = read_efuse_byte,
.adapter_start = rtl_pci_start,
.adapter_stop = rtl_pci_stop,
+ .check_buddy_priv = rtl_pci_check_buddy_priv,
.adapter_tx = rtl_pci_tx,
.flush = rtl_pci_flush,
.reset_trx_ring = rtl_pci_reset_trx_ring,