diff options
author | Adam Lee <adam.lee@canonical.com> | 2014-03-27 23:36:18 -0400 |
---|---|---|
committer | John W. Linville <linville@tuxdriver.com> | 2014-03-31 13:47:41 -0400 |
commit | 94010fa0dd07e8b904e7c6b6589f15573008ab15 (patch) | |
tree | d26c0bd3391c7b1dec8f371f4901c681eaf8ab4a /drivers/net/wireless/rtlwifi | |
parent | 52250cbee7f62400140295a632e0ffbbe5b083ca (diff) |
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: Adam Lee <adam.lee@canonical.com>
Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/rtlwifi')
-rw-r--r-- | drivers/net/wireless/rtlwifi/pci.c | 65 |
1 files changed, 63 insertions, 2 deletions
diff --git a/drivers/net/wireless/rtlwifi/pci.c b/drivers/net/wireless/rtlwifi/pci.c index 7d711708d2f3..dae55257f0e8 100644 --- a/drivers/net/wireless/rtlwifi/pci.c +++ b/drivers/net/wireless/rtlwifi/pci.c | |||
@@ -1853,6 +1853,65 @@ static bool _rtl_pci_find_adapter(struct pci_dev *pdev, | |||
1853 | return true; | 1853 | return true; |
1854 | } | 1854 | } |
1855 | 1855 | ||
1856 | static int rtl_pci_intr_mode_msi(struct ieee80211_hw *hw) | ||
1857 | { | ||
1858 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
1859 | struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); | ||
1860 | struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); | ||
1861 | int ret; | ||
1862 | |||
1863 | ret = pci_enable_msi(rtlpci->pdev); | ||
1864 | if (ret < 0) | ||
1865 | return ret; | ||
1866 | |||
1867 | ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, | ||
1868 | IRQF_SHARED, KBUILD_MODNAME, hw); | ||
1869 | if (ret < 0) { | ||
1870 | pci_disable_msi(rtlpci->pdev); | ||
1871 | return ret; | ||
1872 | } | ||
1873 | |||
1874 | rtlpci->using_msi = true; | ||
1875 | |||
1876 | RT_TRACE(rtlpriv, COMP_INIT|COMP_INTR, DBG_DMESG, | ||
1877 | "MSI Interrupt Mode!\n"); | ||
1878 | return 0; | ||
1879 | } | ||
1880 | |||
1881 | static int rtl_pci_intr_mode_legacy(struct ieee80211_hw *hw) | ||
1882 | { | ||
1883 | struct rtl_priv *rtlpriv = rtl_priv(hw); | ||
1884 | struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); | ||
1885 | struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); | ||
1886 | int ret; | ||
1887 | |||
1888 | ret = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, | ||
1889 | IRQF_SHARED, KBUILD_MODNAME, hw); | ||
1890 | if (ret < 0) | ||
1891 | return ret; | ||
1892 | |||
1893 | rtlpci->using_msi = false; | ||
1894 | RT_TRACE(rtlpriv, COMP_INIT|COMP_INTR, DBG_DMESG, | ||
1895 | "Pin-based Interrupt Mode!\n"); | ||
1896 | return 0; | ||
1897 | } | ||
1898 | |||
1899 | static int rtl_pci_intr_mode_decide(struct ieee80211_hw *hw) | ||
1900 | { | ||
1901 | struct rtl_pci_priv *pcipriv = rtl_pcipriv(hw); | ||
1902 | struct rtl_pci *rtlpci = rtl_pcidev(pcipriv); | ||
1903 | int ret; | ||
1904 | |||
1905 | if (rtlpci->msi_support) { | ||
1906 | ret = rtl_pci_intr_mode_msi(hw); | ||
1907 | if (ret < 0) | ||
1908 | ret = rtl_pci_intr_mode_legacy(hw); | ||
1909 | } else { | ||
1910 | ret = rtl_pci_intr_mode_legacy(hw); | ||
1911 | } | ||
1912 | return ret; | ||
1913 | } | ||
1914 | |||
1856 | int rtl_pci_probe(struct pci_dev *pdev, | 1915 | int rtl_pci_probe(struct pci_dev *pdev, |
1857 | const struct pci_device_id *id) | 1916 | const struct pci_device_id *id) |
1858 | { | 1917 | { |
@@ -1995,8 +2054,7 @@ int rtl_pci_probe(struct pci_dev *pdev, | |||
1995 | } | 2054 | } |
1996 | 2055 | ||
1997 | rtlpci = rtl_pcidev(pcipriv); | 2056 | rtlpci = rtl_pcidev(pcipriv); |
1998 | err = request_irq(rtlpci->pdev->irq, &_rtl_pci_interrupt, | 2057 | err = rtl_pci_intr_mode_decide(hw); |
1999 | IRQF_SHARED, KBUILD_MODNAME, hw); | ||
2000 | if (err) { | 2058 | if (err) { |
2001 | RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, | 2059 | RT_TRACE(rtlpriv, COMP_INIT, DBG_DMESG, |
2002 | "%s: failed to register IRQ handler\n", | 2060 | "%s: failed to register IRQ handler\n", |
@@ -2064,6 +2122,9 @@ void rtl_pci_disconnect(struct pci_dev *pdev) | |||
2064 | rtlpci->irq_alloc = 0; | 2122 | rtlpci->irq_alloc = 0; |
2065 | } | 2123 | } |
2066 | 2124 | ||
2125 | if (rtlpci->using_msi) | ||
2126 | pci_disable_msi(rtlpci->pdev); | ||
2127 | |||
2067 | list_del(&rtlpriv->list); | 2128 | list_del(&rtlpriv->list); |
2068 | if (rtlpriv->io.pci_mem_start != 0) { | 2129 | if (rtlpriv->io.pci_mem_start != 0) { |
2069 | pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); | 2130 | pci_iounmap(pdev, (void __iomem *)rtlpriv->io.pci_mem_start); |