diff options
Diffstat (limited to 'drivers/net/wireless/rtlwifi/pci.c')
-rw-r--r-- | drivers/net/wireless/rtlwifi/pci.c | 267 |
1 files changed, 136 insertions, 131 deletions
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index a40952845436..5efd57833489 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c @@ -35,10 +35,10 @@ #include "efuse.h" static const u16 pcibridge_vendors[PCI_BRIDGE_VENDOR_MAX] = { - INTEL_VENDOR_ID, - ATI_VENDOR_ID, - AMD_VENDOR_ID, - SIS_VENDOR_ID + PCI_VENDOR_ID_INTEL, + PCI_VENDOR_ID_ATI, + PCI_VENDOR_ID_AMD, + PCI_VENDOR_ID_SI }; static const u8 ac_to_hwq[] = { @@ -390,7 +390,7 @@ static void rtl_pci_parse_configuration(struct pci_dev *pdev, u8 linkctrl_reg; /*Link Control Register */ - pos = pci_find_capability(pdev, PCI_CAP_ID_EXP); + pos = pci_pcie_cap(pdev); pci_read_config_byte(pdev, pos + PCI_EXP_LNKCTL, &linkctrl_reg); pcipriv->ndis_adapter.linkctrl_reg = linkctrl_reg; @@ -581,7 +581,7 @@ static void _rtl_pci_tx_isr(struct ieee80211_hw *hw, int prio) fc = rtl_get_fc(skb); if (ieee80211_is_nullfunc(fc)) { if (ieee80211_has_pm(fc)) { - rtlpriv->mac80211.offchan_deley = true; + rtlpriv->mac80211.offchan_delay = true; rtlpriv->psc.state_inap = 1; } else { rtlpriv->psc.state_inap = 0; @@ -622,10 +622,60 @@ tx_status_ok: if (((rtlpriv->link_info.num_rx_inperiod + rtlpriv->link_info.num_tx_inperiod) > 8) || (rtlpriv->link_info.num_rx_inperiod > 2)) { - rtl_lps_leave(hw); + tasklet_schedule(&rtlpriv->works.ips_leave_tasklet); } } +static void _rtl_receive_one(struct ieee80211_hw *hw, struct sk_buff *skb, + struct ieee80211_rx_status rx_status) +{ + struct rtl_priv *rtlpriv = rtl_priv(hw); + struct ieee80211_hdr *hdr = rtl_get_hdr(skb); + __le16 fc = rtl_get_fc(skb); + bool unicast = false; + struct sk_buff *uskb = NULL; + u8 *pdata; + + + memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, sizeof(rx_status)); + + if (is_broadcast_ether_addr(hdr->addr1)) { + ;/*TODO*/ + } else if (is_multicast_ether_addr(hdr->addr1)) { + ;/*TODO*/ + } else { + unicast = true; + rtlpriv->stats.rxbytesunicast += skb->len; + } + + rtl_is_special_data(hw, skb, false); + + if (ieee80211_is_data(fc)) { + rtlpriv->cfg->ops->led_control(hw, LED_CTL_RX); + + if (unicast) + rtlpriv->link_info.num_rx_inperiod++; + } + + /* for sw lps */ + rtl_swlps_beacon(hw, (void *)skb->data, skb->len); + rtl_recognize_peer(hw, (void *)skb->data, skb->len); + if ((rtlpriv->mac80211.opmode == NL80211_IFTYPE_AP) && + (rtlpriv->rtlhal.current_bandtype == BAND_ON_2_4G) && + (ieee80211_is_beacon(fc) || ieee80211_is_probe_resp(fc))) + return; + + if (unlikely(!rtl_action_proc(hw, skb, false))) + return; + + uskb = dev_alloc_skb(skb->len + 128); + 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,185 +687,112 @@ static void _rtl_pci_rx_interrupt(struct ieee80211_hw *hw) u8 own; u8 tmp_one; u32 bufferaddress; - bool unicast = false; struct rtl_stats stats = { .signal = 0, .noise = -98, .rate = 0, }; + int index = rtlpci->rx_ring[rx_queue_idx].idx; /*RX NORMAL PKT */ while (count--) { /*rx descriptor */ struct rtl_rx_desc *pdesc = &rtlpci->rx_ring[rx_queue_idx].desc[ - rtlpci->rx_ring[rx_queue_idx].idx]; + index]; /*rx pkt */ struct sk_buff *skb = rtlpci->rx_ring[rx_queue_idx].rx_buf[ - rtlpci->rx_ring[rx_queue_idx].idx]; + index]; + struct sk_buff *new_skb = NULL; own = (u8) rtlpriv->cfg->ops->get_desc((u8 *) pdesc, false, HW_DESC_OWN); - if (own) { - /*wait data to be filled by hardware */ - return; - } else { - struct ieee80211_hdr *hdr; - __le16 fc; - struct sk_buff *new_skb = NULL; + /*wait data to be filled by hardware */ + if (own) + break; - rtlpriv->cfg->ops->query_rx_desc(hw, &stats, - &rx_status, - (u8 *) pdesc, skb); + rtlpriv->cfg->ops->query_rx_desc(hw, &stats, + &rx_status, + (u8 *) pdesc, skb); - pci_unmap_single(rtlpci->pdev, - *((dma_addr_t *) skb->cb), - rtlpci->rxbuffersize, - PCI_DMA_FROMDEVICE); + if (stats.crc || stats.hwerror) + goto done; + + new_skb = dev_alloc_skb(rtlpci->rxbuffersize); + if (unlikely(!new_skb)) { + RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), + DBG_DMESG, + ("can't alloc skb for rx\n")); + goto done; + } - skb_put(skb, rtlpriv->cfg->ops->get_desc((u8 *) pdesc, - false, - HW_DESC_RXPKT_LEN)); - skb_reserve(skb, - stats.rx_drvinfo_size + stats.rx_bufshift); + pci_unmap_single(rtlpci->pdev, + *((dma_addr_t *) skb->cb), + rtlpci->rxbuffersize, + PCI_DMA_FROMDEVICE); - /* - *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); - */ + 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); - hdr = rtl_get_hdr(skb); - fc = rtl_get_fc(skb); - - if (!stats.crc || !stats.hwerror) { - memcpy(IEEE80211_SKB_RXCB(skb), &rx_status, - sizeof(rx_status)); - - if (is_broadcast_ether_addr(hdr->addr1)) { - ;/*TODO*/ - } else if (is_multicast_ether_addr(hdr->addr1)) { - ;/*TODO*/ - } else { - unicast = true; - rtlpriv->stats.rxbytesunicast += - skb->len; - } - - rtl_is_special_data(hw, skb, false); - - if (ieee80211_is_data(fc)) { - rtlpriv->cfg->ops->led_control(hw, - LED_CTL_RX); - - if (unicast) - rtlpriv->link_info. - num_rx_inperiod++; - } - - /* for sw lps */ - rtl_swlps_beacon(hw, (void *)skb->data, - skb->len); - rtl_recognize_peer(hw, (void *)skb->data, - skb->len); - if ((rtlpriv->mac80211.opmode == - NL80211_IFTYPE_AP) && - (rtlpriv->rtlhal.current_bandtype == - BAND_ON_2_4G) && - (ieee80211_is_beacon(fc) || - ieee80211_is_probe_resp(fc))) { - dev_kfree_skb_any(skb); - } else { - if (unlikely(!rtl_action_proc(hw, skb, - false))) { - dev_kfree_skb_any(skb); - } else { - struct sk_buff *uskb = NULL; - u8 *pdata; - uskb = dev_alloc_skb(skb->len - + 128); - memcpy(IEEE80211_SKB_RXCB(uskb), - &rx_status, - sizeof(rx_status)); - pdata = (u8 *)skb_put(uskb, - skb->len); - memcpy(pdata, skb->data, - skb->len); - dev_kfree_skb_any(skb); - - ieee80211_rx_irqsafe(hw, uskb); - } - } - } else { - dev_kfree_skb_any(skb); - } + /* + * 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); - new_skb = dev_alloc_skb(rtlpci->rxbuffersize); - if (unlikely(!new_skb)) { - RT_TRACE(rtlpriv, (COMP_INTR | COMP_RECV), - DBG_DMESG, - ("can't alloc skb for rx\n")); - goto done; - } - skb = new_skb; - /*skb->dev = dev; */ + if (((rtlpriv->link_info.num_rx_inperiod + + rtlpriv->link_info.num_tx_inperiod) > 8) || + (rtlpriv->link_info.num_rx_inperiod > 2)) { + tasklet_schedule(&rtlpriv->works.ips_leave_tasklet); + } - rtlpci->rx_ring[rx_queue_idx].rx_buf[rtlpci-> - rx_ring - [rx_queue_idx]. - idx] = skb; - *((dma_addr_t *) skb->cb) = + dev_kfree_skb_any(skb); + skb = new_skb; + + rtlpci->rx_ring[rx_queue_idx].rx_buf[index] = skb; + *((dma_addr_t *) skb->cb) = pci_map_single(rtlpci->pdev, skb_tail_pointer(skb), rtlpci->rxbuffersize, PCI_DMA_FROMDEVICE); - } done: bufferaddress = (*((dma_addr_t *)skb->cb)); tmp_one = 1; rtlpriv->cfg->ops->set_desc((u8 *) pdesc, false, HW_DESC_RXBUFF_ADDR, (u8 *)&bufferaddress); - rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN, - (u8 *)&tmp_one); rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXPKT_LEN, (u8 *)&rtlpci->rxbuffersize); - if (rtlpci->rx_ring[rx_queue_idx].idx == - rtlpci->rxringcount - 1) + if (index == rtlpci->rxringcount - 1) rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXERO, (u8 *)&tmp_one); - rtlpci->rx_ring[rx_queue_idx].idx = - (rtlpci->rx_ring[rx_queue_idx].idx + 1) % - rtlpci->rxringcount; + rtlpriv->cfg->ops->set_desc((u8 *)pdesc, false, HW_DESC_RXOWN, + (u8 *)&tmp_one); + + index = (index + 1) % rtlpci->rxringcount; } + rtlpci->rx_ring[rx_queue_idx].idx = index; } static irqreturn_t _rtl_pci_interrupt(int irq, void *dev_id) { struct ieee80211_hw *hw = dev_id; struct rtl_priv *rtlpriv = rtl_priv(hw); - struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); struct rtl_hal *rtlhal = rtl_hal(rtl_priv(hw)); unsigned long flags; u32 inta = 0; u32 intb = 0; - if (rtlpci->irq_enabled == 0) - return IRQ_HANDLED; - spin_lock_irqsave(&rtlpriv->locks.irq_th_lock, flags); /*read ISR: 4/8bytes */ @@ -938,6 +915,11 @@ static void _rtl_pci_irq_tasklet(struct ieee80211_hw *hw) _rtl_pci_tx_chk_waitq(hw); } +static void _rtl_pci_ips_leave_tasklet(struct ieee80211_hw *hw) +{ + rtl_lps_leave(hw); +} + static void _rtl_pci_prepare_bcn_tasklet(struct ieee80211_hw *hw) { struct rtl_priv *rtlpriv = rtl_priv(hw); @@ -1036,6 +1018,9 @@ static void _rtl_pci_init_struct(struct ieee80211_hw *hw, tasklet_init(&rtlpriv->works.irq_prepare_bcn_tasklet, (void (*)(unsigned long))_rtl_pci_prepare_bcn_tasklet, (unsigned long)hw); + tasklet_init(&rtlpriv->works.ips_leave_tasklet, + (void (*)(unsigned long))_rtl_pci_ips_leave_tasklet, + (unsigned long)hw); } static int _rtl_pci_init_tx_ring(struct ieee80211_hw *hw, @@ -1113,6 +1098,13 @@ static int _rtl_pci_init_rx_ring(struct ieee80211_hw *hw) rtlpci->rx_ring[rx_queue_idx].idx = 0; + /* If amsdu_8k is disabled, set buffersize to 4096. This + * change will reduce memory fragmentation. + */ + if (rtlpci->rxbuffersize > 4096 && + rtlpriv->rtlhal.disable_amsdu_8k) + rtlpci->rxbuffersize = 4096; + for (i = 0; i < rtlpci->rxringcount; i++) { struct sk_buff *skb = dev_alloc_skb(rtlpci->rxbuffersize); @@ -1498,6 +1490,7 @@ static void rtl_pci_deinit(struct ieee80211_hw *hw) synchronize_irq(rtlpci->pdev->irq); tasklet_kill(&rtlpriv->works.irq_tasklet); + tasklet_kill(&rtlpriv->works.ips_leave_tasklet); flush_workqueue(rtlpriv->works.rtl_wq); destroy_workqueue(rtlpriv->works.rtl_wq); @@ -1572,6 +1565,7 @@ static void rtl_pci_stop(struct ieee80211_hw *hw) set_hal_stop(rtlhal); rtlpriv->cfg->ops->disable_interrupt(hw); + tasklet_kill(&rtlpriv->works.ips_leave_tasklet); spin_lock_irqsave(&rtlpriv->locks.rf_ps_lock, flags); while (ppsc->rfchange_inprogress) { @@ -1617,6 +1611,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 || @@ -1849,7 +1853,8 @@ int __devinit rtl_pci_probe(struct pci_dev *pdev, pci_write_config_byte(pdev, 0x04, 0x07); /* find adapter */ - _rtl_pci_find_adapter(pdev, hw); + if (!_rtl_pci_find_adapter(pdev, hw)) + goto fail3; /* Init IO handler */ _rtl_pci_io_handler_init(&pdev->dev, hw); |