]> git.ipfire.org Git - people/pmueller/ipfire-2.x.git/blame - src/patches/suse-2.6.27.31/patches.fixes/iwlagn-fix-rfkill.patch
Add a patch to fix Intel E100 wake-on-lan problems.
[people/pmueller/ipfire-2.x.git] / src / patches / suse-2.6.27.31 / patches.fixes / iwlagn-fix-rfkill.patch
CommitLineData
2cb7cef9
BS
1From: Helmut Schaa <helmut.schaa@googlemail.com>
2Date: Mon Jan 19 13:10:07 2009 +0100
3Subject: iwlagn: fix hw-rfkill while the interface is down
4Patch-mainline: wireless-testing (2.6.30?)
5References: bnc#446158
6
7iwlagn: fix hw-rfkill while the interface is down
8
9Currently iwlagn is not able to report hw-killswitch events while the
10interface is down. This has implications on user space tools (like
11NetworkManager) relying on rfkill notifications to bring the interface
12up once the wireless gets enabled through a hw killswitch.
13
14Thus, enable the device already in iwl_pci_probe instead of iwl_up
15and enable interrups while the interface is down in order to get
16notified about killswitch state changes. The firmware loading is still
17done in iwl_up.
18
19Signed-off-by: Helmut Schaa <helmut.schaa@googlemail.com>
20Acked-by: Reinette Chatre <reinette.chatre@intel.com>
21Signed-off-by: John W. Linville <linville@tuxdriver.com>
22Acked-by: Helmut Schaa <hschaa@suse.de>
23Acked-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);