Commit 94010fa0 authored by Adam Lee's avatar Adam Lee Committed by John W. Linville

rtlwifi: add MSI interrupts mode support

Add MSI interrupts mode support, enable it when submodules' msi_support
flag is true, also could fallback to pin-based interrupts mode if MSI
interrupts mode fails.

RealTek's policy(on modules which work well with MSI interrupts mode) is:

> If the platform supports both MSI and pin-based, use MSI.
> If the platform supports MSI only, use MSI.
> If the platform supports pin-based only, use pin-based.

Also as RealTek's testing results, RTL8188EE and RTL8723BE work well
with both MSI mode and pin-based mode fallback.
Signed-off-by: default avatarAdam Lee <adam.lee@canonical.com>
Signed-off-by: default avatarJohn W. Linville <linville@tuxdriver.com>
parent 52250cbe
...@@ -1853,6 +1853,65 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, ...@@ -1853,6 +1853,65 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev,
return true; return true;
} }
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, int rtl_pci_probe(struct pci_dev *pdev,
const struct pci_device_id *id) const struct pci_device_id *id)
{ {
...@@ -1995,8 +2054,7 @@ int rtl_pci_probe(struct pci_dev *pdev, ...@@ -1995,8 +2054,7 @@ int rtl_pci_probe(struct pci_dev *pdev,
} }
rtlpci = rtl_pcidev(pcipriv); rtlpci = rtl_pcidev(pcipriv);
err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, err = rtl_pci_intr_mode_decide(hw);
IRQF_SHARED, KBUILD_MODNAME, hw);
if (err) { if (err) {
RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG,
"%s: failed to register IRQ handler\n", "%s: failed to register IRQ handler\n",
...@@ -2064,6 +2122,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev) ...@@ -2064,6 +2122,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev)
rtlpci->irq_alloc = 0; rtlpci->irq_alloc = 0;
} }
if (rtlpci->using_msi)
pci_disable_msi(rtlpci->pdev);
list_del(&rtlpriv->list); list_del(&rtlpriv->list);
if (rtlpriv->io.pci_mem_start != 0) { if (rtlpriv->io.pci_mem_start != 0) {
pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start);
......
Markdown is supported
0%
or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment