]>
Commit | Line | Data |
---|---|---|
00e5a55c BS |
1 | From: Helmut Schaa <helmut.schaa@googlemail.com> |
2 | Date: Mon Jan 19 13:10:07 2009 +0100 | |
3 | Subject: iwlagn: fix hw-rfkill while the interface is down | |
4 | Patch-mainline: wireless-testing (2.6.30?) | |
5 | References: bnc#446158 | |
6 | ||
7 | iwlagn: fix hw-rfkill while the interface is down | |
8 | ||
9 | Currently iwlagn is not able to report hw-killswitch events while the | |
10 | interface is down. This has implications on user space tools (like | |
11 | NetworkManager) relying on rfkill notifications to bring the interface | |
12 | up once the wireless gets enabled through a hw killswitch. | |
13 | ||
14 | Thus, enable the device already in iwl_pci_probe instead of iwl_up | |
15 | and enable interrups while the interface is down in order to get | |
16 | notified about killswitch state changes. The firmware loading is still | |
17 | done in iwl_up. | |
18 | ||
19 | Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com> | |
20 | Acked-by: Reinette Chatre <reinette.chatre@intel.com> | |
21 | Signed-off-by: John W. Linville <linville@tuxdriver.com> | |
22 | Acked-by: Helmut Schaa <hschaa@suse.de> | |
23 | Acked-by: Jiri Benc <jbenc@suse.cz> | |
24 | ||
25 | --- | |
26 | drivers/net/wireless/iwlwifi/iwl-agn.c | 111 +++++++++++++++++---------------- | |
27 | 1 file changed, 58 insertions(+), 53 deletions(-) | |
28 | ||
29 | --- linux-2.6.27.orig/drivers/net/wireless/iwlwifi/iwl-agn.c | |
30 | +++ linux-2.6.27/drivers/net/wireless/iwlwifi/iwl-agn.c | |
31 | @@ -1643,11 +1643,17 @@ static void iwl4965_irq_tasklet(struct i | |
32 | hw_rf_kill ? "disable radio":"enable radio"); | |
33 | ||
34 | /* driver only loads ucode once setting the interface up. | |
35 | - * the driver as well won't allow loading if RFKILL is set | |
36 | - * therefore no need to restart the driver from this handler | |
37 | - */ | |
38 | - if (!hw_rf_kill && !test_bit(STATUS_ALIVE, &priv->status)) | |
39 | - clear_bit(STATUS_RF_KILL_HW, &priv->status); | |
40 | + * the driver allows loading the ucode even if the radio | |
41 | + * is killed. Hence update the killswitch state here. The | |
42 | + * rfkill handler will care about restarting if needed. | |
43 | + */ | |
44 | + if (!test_bit(STATUS_ALIVE, &priv->status)) { | |
45 | + if (hw_rf_kill) | |
46 | + set_bit(STATUS_RF_KILL_HW, &priv->status); | |
47 | + else | |
48 | + clear_bit(STATUS_RF_KILL_HW, &priv->status); | |
49 | + queue_work(priv->workqueue, &priv->rf_kill); | |
50 | + } | |
51 | ||
52 | handled |= CSR_INT_BIT_RF_KILL; | |
53 | } | |
54 | @@ -2349,7 +2355,8 @@ static void iwl4965_bg_rf_kill(struct wo | |
55 | IWL_DEBUG(IWL_DL_RF_KILL, | |
56 | "HW and/or SW RF Kill no longer active, restarting " | |
57 | "device\n"); | |
58 | - if (!test_bit(STATUS_EXIT_PENDING, &priv->status)) | |
59 | + if (!test_bit(STATUS_EXIT_PENDING, &priv->status) && | |
60 | + test_bit(STATUS_ALIVE, &priv->status)) | |
61 | queue_work(priv->workqueue, &priv->restart); | |
62 | } else { | |
63 | /* make sure mac80211 stop sending Tx frame */ | |
64 | @@ -2593,31 +2600,9 @@ static int iwl4965_mac_start(struct ieee | |
65 | { | |
66 | struct iwl_priv *priv = hw->priv; | |
67 | int ret; | |
68 | - u16 pci_cmd; | |
69 | ||
70 | IWL_DEBUG_MAC80211("enter\n"); | |
71 | ||
72 | - if (pci_enable_device(priv->pci_dev)) { | |
73 | - IWL_ERROR("Fail to pci_enable_device\n"); | |
74 | - return -ENODEV; | |
75 | - } | |
76 | - pci_restore_state(priv->pci_dev); | |
77 | - pci_enable_msi(priv->pci_dev); | |
78 | - | |
79 | - /* enable interrupts if needed: hw bug w/a */ | |
80 | - pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); | |
81 | - if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { | |
82 | - pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; | |
83 | - pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); | |
84 | - } | |
85 | - | |
86 | - ret = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, | |
87 | - DRV_NAME, priv); | |
88 | - if (ret) { | |
89 | - IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); | |
90 | - goto out_disable_msi; | |
91 | - } | |
92 | - | |
93 | /* we should be verifying the device is ready to be opened */ | |
94 | mutex_lock(&priv->mutex); | |
95 | ||
96 | @@ -2630,7 +2615,7 @@ static int iwl4965_mac_start(struct ieee | |
97 | if (ret) { | |
98 | IWL_ERROR("Could not read microcode: %d\n", ret); | |
99 | mutex_unlock(&priv->mutex); | |
100 | - goto out_release_irq; | |
101 | + return ret; | |
102 | } | |
103 | } | |
104 | ||
105 | @@ -2641,7 +2626,7 @@ static int iwl4965_mac_start(struct ieee | |
106 | iwl_rfkill_set_hw_state(priv); | |
107 | ||
108 | if (ret) | |
109 | - goto out_release_irq; | |
110 | + return ret; | |
111 | ||
112 | if (iwl_is_rfkill(priv)) | |
113 | goto out; | |
114 | @@ -2660,8 +2645,7 @@ static int iwl4965_mac_start(struct ieee | |
115 | if (!test_bit(STATUS_READY, &priv->status)) { | |
116 | IWL_ERROR("START_ALIVE timeout after %dms.\n", | |
117 | jiffies_to_msecs(UCODE_READY_TIMEOUT)); | |
118 | - ret = -ETIMEDOUT; | |
119 | - goto out_release_irq; | |
120 | + return -ETIMEDOUT; | |
121 | } | |
122 | } | |
123 | ||
124 | @@ -2669,15 +2653,6 @@ out: | |
125 | priv->is_open = 1; | |
126 | IWL_DEBUG_MAC80211("leave\n"); | |
127 | return 0; | |
128 | - | |
129 | -out_release_irq: | |
130 | - free_irq(priv->pci_dev->irq, priv); | |
131 | -out_disable_msi: | |
132 | - pci_disable_msi(priv->pci_dev); | |
133 | - pci_disable_device(priv->pci_dev); | |
134 | - priv->is_open = 0; | |
135 | - IWL_DEBUG_MAC80211("leave - failed\n"); | |
136 | - return ret; | |
137 | } | |
138 | ||
139 | static void iwl4965_mac_stop(struct ieee80211_hw *hw) | |
140 | @@ -2705,10 +2680,10 @@ static void iwl4965_mac_stop(struct ieee | |
141 | iwl4965_down(priv); | |
142 | ||
143 | flush_workqueue(priv->workqueue); | |
144 | - free_irq(priv->pci_dev->irq, priv); | |
145 | - pci_disable_msi(priv->pci_dev); | |
146 | - pci_save_state(priv->pci_dev); | |
147 | - pci_disable_device(priv->pci_dev); | |
148 | + | |
149 | + /* enable interrupts again in order to receive rfkill changes */ | |
150 | + iwl_write32(priv, CSR_INT, 0xFFFFFFFF); | |
151 | + iwl4965_enable_interrupts(priv); | |
152 | ||
153 | IWL_DEBUG_MAC80211("leave\n"); | |
154 | } | |
155 | @@ -4176,6 +4151,7 @@ static int iwl4965_pci_probe(struct pci_ | |
156 | struct iwl_cfg *cfg = (struct iwl_cfg *)(ent->driver_data); | |
157 | unsigned long flags; | |
158 | DECLARE_MAC_BUF(mac); | |
159 | + u16 pci_cmd; | |
160 | ||
161 | /************************ | |
162 | * 1. Allocating HW data | |
163 | @@ -4320,26 +4296,36 @@ static int iwl4965_pci_probe(struct pci_ | |
164 | iwl4965_disable_interrupts(priv); | |
165 | spin_unlock_irqrestore(&priv->lock, flags); | |
166 | ||
167 | + pci_enable_msi(priv->pci_dev); | |
168 | + | |
169 | + err = request_irq(priv->pci_dev->irq, iwl4965_isr, IRQF_SHARED, | |
170 | + DRV_NAME, priv); | |
171 | + if (err) { | |
172 | + IWL_ERROR("Error allocating IRQ %d\n", priv->pci_dev->irq); | |
173 | + goto out_disable_msi; | |
174 | + } | |
175 | err = sysfs_create_group(&pdev->dev.kobj, &iwl4965_attribute_group); | |
176 | if (err) { | |
177 | IWL_ERROR("failed to create sysfs device attributes\n"); | |
178 | goto out_uninit_drv; | |
179 | } | |
180 | ||
181 | - | |
182 | iwl_setup_deferred_work(priv); | |
183 | iwl_setup_rx_handlers(priv); | |
184 | ||
185 | - /******************** | |
186 | - * 9. Conclude | |
187 | - ********************/ | |
188 | - pci_save_state(pdev); | |
189 | - pci_disable_device(pdev); | |
190 | - | |
191 | /********************************** | |
192 | - * 10. Setup and register mac80211 | |
193 | + * 9. Setup and register mac80211 | |
194 | **********************************/ | |
195 | ||
196 | + /* enable interrupts if needed: hw bug w/a */ | |
197 | + pci_read_config_word(priv->pci_dev, PCI_COMMAND, &pci_cmd); | |
198 | + if (pci_cmd & PCI_COMMAND_INTX_DISABLE) { | |
199 | + pci_cmd &= ~PCI_COMMAND_INTX_DISABLE; | |
200 | + pci_write_config_word(priv->pci_dev, PCI_COMMAND, pci_cmd); | |
201 | + } | |
202 | + | |
203 | + iwl4965_enable_interrupts(priv); | |
204 | + | |
205 | err = iwl_setup_mac(priv); | |
206 | if (err) | |
207 | goto out_remove_sysfs; | |
208 | @@ -4348,15 +4334,27 @@ static int iwl4965_pci_probe(struct pci_ | |
209 | if (err) | |
210 | IWL_ERROR("failed to create debugfs files\n"); | |
211 | ||
212 | + /* If platform's RF_KILL switch is NOT set to KILL */ | |
213 | + if (iwl_read32(priv, CSR_GP_CNTRL) & CSR_GP_CNTRL_REG_FLAG_HW_RF_KILL_SW) | |
214 | + clear_bit(STATUS_RF_KILL_HW, &priv->status); | |
215 | + else | |
216 | + set_bit(STATUS_RF_KILL_HW, &priv->status); | |
217 | + | |
218 | err = iwl_rfkill_init(priv); | |
219 | if (err) | |
220 | IWL_ERROR("Unable to initialize RFKILL system. " | |
221 | "Ignoring error: %d\n", err); | |
222 | + else | |
223 | + iwl_rfkill_set_hw_state(priv); | |
224 | + | |
225 | iwl_power_initialize(priv); | |
226 | return 0; | |
227 | ||
228 | out_remove_sysfs: | |
229 | sysfs_remove_group(&pdev->dev.kobj, &iwl4965_attribute_group); | |
230 | + out_disable_msi: | |
231 | + pci_disable_msi(priv->pci_dev); | |
232 | + pci_disable_device(priv->pci_dev); | |
233 | out_uninit_drv: | |
234 | iwl_uninit_drv(priv); | |
235 | out_free_eeprom: | |
236 | @@ -4428,6 +4426,8 @@ static void __devexit iwl4965_pci_remove | |
237 | destroy_workqueue(priv->workqueue); | |
238 | priv->workqueue = NULL; | |
239 | ||
240 | + free_irq(priv->pci_dev->irq, priv); | |
241 | + pci_disable_msi(priv->pci_dev); | |
242 | pci_iounmap(pdev, priv->hw_base); | |
243 | pci_release_regions(pdev); | |
244 | pci_disable_device(pdev); | |
245 | @@ -4453,6 +4453,8 @@ static int iwl4965_pci_suspend(struct pc | |
246 | priv->is_open = 1; | |
247 | } | |
248 | ||
249 | + pci_save_state(pdev); | |
250 | + pci_disable_device(pdev); | |
251 | pci_set_power_state(pdev, PCI_D3hot); | |
252 | ||
253 | return 0; | |
254 | @@ -4463,6 +4465,9 @@ static int iwl4965_pci_resume(struct pci | |
255 | struct iwl_priv *priv = pci_get_drvdata(pdev); | |
256 | ||
257 | pci_set_power_state(pdev, PCI_D0); | |
258 | + pci_enable_device(pdev); | |
259 | + pci_restore_state(pdev); | |
260 | + iwl4965_enable_interrupts(priv); | |
261 | ||
262 | if (priv->is_open) | |
263 | iwl4965_mac_start(priv->hw); |