diff options
Diffstat (limited to 'drivers/net/wireless/rtlwifi/pci.c')
| -rw-r--r-- | drivers/net/wireless/rtlwifi/pci.c | 661 |
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, |
