]>
Commit | Line | Data |
---|---|---|
f514fb28 GKH |
1 | From 54328e64047a54b8fc2362c2e1f0fa16c90f739f Mon Sep 17 00:00:00 2001 |
2 | From: Larry Finger <Larry.Finger@lwfinger.net> | |
3 | Date: Fri, 2 Oct 2015 11:44:30 -0500 | |
4 | Subject: rtlwifi: rtl8821ae: Fix system lockups on boot | |
5 | ||
6 | From: Larry Finger <Larry.Finger@lwfinger.net> | |
7 | ||
8 | commit 54328e64047a54b8fc2362c2e1f0fa16c90f739f upstream. | |
9 | ||
10 | In commit 1277fa2ab2f9 ("rtlwifi: Remove the clear interrupt routine from all | |
11 | drivers"), the code that cleared all interrupt enable bits before setting them | |
12 | was removed for all PCI drivers. This fixed an issue that caused TX to be | |
13 | blocked for 3-5 seconds. On some RTL8821AE units, this change causes soft | |
14 | lockups to occur on boot. For that reason, the portion of the earlier commit | |
15 | that applied to rtl8821ae is reverted. Kernels 4.1 and newer are affected. | |
16 | ||
17 | See http://marc.info/?l=linux-wireless&m=144373370103285&w=2 and | |
18 | https://bugzilla.opensuse.org/show_bug.cgi?id=944978 for two cases where | |
19 | this regression affected user systems. Note that this bug does not appear on | |
20 | any of the developer's setups. For those users whose systems are affected | |
21 | by the TX blockage, but do not lock up on boot, a module parameter is added | |
22 | to disable the interrupt clear | |
23 | ||
24 | Fixes: 1277fa2ab2f9 ("rtlwifi: Remove the clear interrupt routine from all drivers") | |
25 | Signed-off-by: Larry Finger <Larry.Finger@lwfinger.net> | |
26 | Signed-off-by: Kalle Valo <kvalo@codeaurora.org> | |
27 | Signed-off-by: Greg Kroah-Hartman <gregkh@linuxfoundation.org> | |
28 | ||
29 | --- | |
30 | drivers/net/wireless/rtlwifi/pci.h | 2 ++ | |
31 | drivers/net/wireless/rtlwifi/rtl8821ae/hw.c | 17 +++++++++++++++++ | |
32 | drivers/net/wireless/rtlwifi/rtl8821ae/sw.c | 5 +++++ | |
33 | drivers/net/wireless/rtlwifi/wifi.h | 3 +++ | |
34 | 4 files changed, 27 insertions(+) | |
35 | ||
36 | --- a/drivers/net/wireless/rtlwifi/pci.h | |
37 | +++ b/drivers/net/wireless/rtlwifi/pci.h | |
38 | @@ -247,6 +247,8 @@ struct rtl_pci { | |
39 | /* MSI support */ | |
40 | bool msi_support; | |
41 | bool using_msi; | |
42 | + /* interrupt clear before set */ | |
43 | + bool int_clear; | |
44 | }; | |
45 | ||
46 | struct mp_adapter { | |
47 | --- a/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c | |
48 | +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/hw.c | |
49 | @@ -2253,11 +2253,28 @@ void rtl8821ae_set_qos(struct ieee80211_ | |
50 | } | |
51 | } | |
52 | ||
53 | +static void rtl8821ae_clear_interrupt(struct ieee80211_hw *hw) | |
54 | +{ | |
55 | + struct rtl_priv *rtlpriv = rtl_priv(hw); | |
56 | + u32 tmp = rtl_read_dword(rtlpriv, REG_HISR); | |
57 | + | |
58 | + rtl_write_dword(rtlpriv, REG_HISR, tmp); | |
59 | + | |
60 | + tmp = rtl_read_dword(rtlpriv, REG_HISRE); | |
61 | + rtl_write_dword(rtlpriv, REG_HISRE, tmp); | |
62 | + | |
63 | + tmp = rtl_read_dword(rtlpriv, REG_HSISR); | |
64 | + rtl_write_dword(rtlpriv, REG_HSISR, tmp); | |
65 | +} | |
66 | + | |
67 | void rtl8821ae_enable_interrupt(struct ieee80211_hw *hw) | |
68 | { | |
69 | struct rtl_priv *rtlpriv = rtl_priv(hw); | |
70 | struct rtl_pci *rtlpci = rtl_pcidev(rtl_pcipriv(hw)); | |
71 | ||
72 | + if (!rtlpci->int_clear) | |
73 | + rtl8821ae_clear_interrupt(hw);/*clear it here first*/ | |
74 | + | |
75 | rtl_write_dword(rtlpriv, REG_HIMR, rtlpci->irq_mask[0] & 0xFFFFFFFF); | |
76 | rtl_write_dword(rtlpriv, REG_HIMRE, rtlpci->irq_mask[1] & 0xFFFFFFFF); | |
77 | rtlpci->irq_enabled = true; | |
78 | --- a/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c | |
79 | +++ b/drivers/net/wireless/rtlwifi/rtl8821ae/sw.c | |
80 | @@ -96,6 +96,7 @@ int rtl8821ae_init_sw_vars(struct ieee80 | |
81 | ||
82 | rtl8821ae_bt_reg_init(hw); | |
83 | rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; | |
84 | + rtlpci->int_clear = rtlpriv->cfg->mod_params->int_clear; | |
85 | rtlpriv->btcoexist.btc_ops = rtl_btc_get_ops_pointer(); | |
86 | ||
87 | rtlpriv->dm.dm_initialgain_enable = 1; | |
88 | @@ -167,6 +168,7 @@ int rtl8821ae_init_sw_vars(struct ieee80 | |
89 | rtlpriv->psc.swctrl_lps = rtlpriv->cfg->mod_params->swctrl_lps; | |
90 | rtlpriv->psc.fwctrl_lps = rtlpriv->cfg->mod_params->fwctrl_lps; | |
91 | rtlpci->msi_support = rtlpriv->cfg->mod_params->msi_support; | |
92 | + rtlpci->msi_support = rtlpriv->cfg->mod_params->int_clear; | |
93 | if (rtlpriv->cfg->mod_params->disable_watchdog) | |
94 | pr_info("watchdog disabled\n"); | |
95 | rtlpriv->psc.reg_fwctrl_lps = 3; | |
96 | @@ -308,6 +310,7 @@ static struct rtl_mod_params rtl8821ae_m | |
97 | .swctrl_lps = false, | |
98 | .fwctrl_lps = true, | |
99 | .msi_support = true, | |
100 | + .int_clear = true, | |
101 | .debug = DBG_EMERG, | |
102 | .disable_watchdog = 0, | |
103 | }; | |
104 | @@ -437,6 +440,7 @@ module_param_named(fwlps, rtl8821ae_mod_ | |
105 | module_param_named(msi, rtl8821ae_mod_params.msi_support, bool, 0444); | |
106 | module_param_named(disable_watchdog, rtl8821ae_mod_params.disable_watchdog, | |
107 | bool, 0444); | |
108 | +module_param_named(int_clear, rtl8821ae_mod_params.int_clear, bool, 0444); | |
109 | MODULE_PARM_DESC(swenc, "Set to 1 for software crypto (default 0)\n"); | |
110 | MODULE_PARM_DESC(ips, "Set to 0 to not use link power save (default 1)\n"); | |
111 | MODULE_PARM_DESC(swlps, "Set to 1 to use SW control power save (default 0)\n"); | |
112 | @@ -444,6 +448,7 @@ MODULE_PARM_DESC(fwlps, "Set to 1 to use | |
113 | MODULE_PARM_DESC(msi, "Set to 1 to use MSI interrupts mode (default 1)\n"); | |
114 | MODULE_PARM_DESC(debug, "Set debug level (0-5) (default 0)"); | |
115 | MODULE_PARM_DESC(disable_watchdog, "Set to 1 to disable the watchdog (default 0)\n"); | |
116 | +MODULE_PARM_DESC(int_clear, "Set to 1 to disable interrupt clear before set (default 0)\n"); | |
117 | ||
118 | static SIMPLE_DEV_PM_OPS(rtlwifi_pm_ops, rtl_pci_suspend, rtl_pci_resume); | |
119 | ||
120 | --- a/drivers/net/wireless/rtlwifi/wifi.h | |
121 | +++ b/drivers/net/wireless/rtlwifi/wifi.h | |
122 | @@ -2234,6 +2234,9 @@ struct rtl_mod_params { | |
123 | ||
124 | /* default 0: 1 means disable */ | |
125 | bool disable_watchdog; | |
126 | + | |
127 | + /* default 0: 1 means do not disable interrupts */ | |
128 | + bool int_clear; | |
129 | }; | |
130 | ||
131 | struct rtl_hal_usbint_cfg { |