aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-03-06 16:30:58 -0500
committerJohn W. Linville <linville@tuxdriver.com>2012-03-07 13:56:32 -0500
commit4bd14dd5f77bbe3c51f50f4e86d3b8960e6a518c (patch)
tree0dbf32e6fbf047035389a09b7b1124ca769a5551 /drivers/net/wireless/iwlwifi
parentf47208934b2aba432722baeb86a72fcbfd26b593 (diff)
iwlwifi: abstract out notification wait support
This will be sharable, but needs to live in the op_mode as it is dependent on command processing. Make a library out of the notification wait code. Since I wrote all of the code originally and only Intel employees changed it, we can also relicense it to dual BSD/GPL. Signed-off-by: Johannes Berg <johannes.berg@intel.com> Signed-off-by: Wey-Yi Guy <wey-yi.w.guy@intel.com> Signed-off-by: John W. Linville <linville@tuxdriver.com>
Diffstat (limited to 'drivers/net/wireless/iwlwifi')
-rw-r--r--drivers/net/wireless/iwlwifi/Makefile1
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rx.c24
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-rxon.c11
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-core.c2
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h3
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-notif-wait.c157
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-notif-wait.h130
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-shared.h55
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-testmode.c10
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-ucode.c81
10 files changed, 314 insertions, 160 deletions
diff --git a/drivers/net/wireless/iwlwifi/Makefile b/drivers/net/wireless/iwlwifi/Makefile
index f2a903d01aa..85d163ed3db 100644
--- a/drivers/net/wireless/iwlwifi/Makefile
+++ b/drivers/net/wireless/iwlwifi/Makefile
@@ -14,6 +14,7 @@ iwlwifi-objs += iwl-1000.o
14iwlwifi-objs += iwl-2000.o 14iwlwifi-objs += iwl-2000.o
15iwlwifi-objs += iwl-pci.o 15iwlwifi-objs += iwl-pci.o
16iwlwifi-objs += iwl-drv.o 16iwlwifi-objs += iwl-drv.o
17iwlwifi-objs += iwl-notif-wait.o
17iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o 18iwlwifi-objs += iwl-trans-pcie.o iwl-trans-pcie-rx.o iwl-trans-pcie-tx.o
18 19
19iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o 20iwlwifi-$(CONFIG_IWLWIFI_DEBUGFS) += iwl-debugfs.o
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
index 5c9c88b8609..f17142bb5df 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rx.c
@@ -1142,9 +1142,7 @@ void iwl_setup_rx_handlers(struct iwl_priv *priv)
1142 priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; 1142 priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
1143 1143
1144 /* set up notification wait support */ 1144 /* set up notification wait support */
1145 spin_lock_init(&priv->shrd->notif_wait_lock); 1145 iwl_notification_wait_init(&priv->notif_wait);
1146 INIT_LIST_HEAD(&priv->shrd->notif_waits);
1147 init_waitqueue_head(&priv->shrd->notif_waitq);
1148 1146
1149 /* Set up BT Rx handlers */ 1147 /* Set up BT Rx handlers */
1150 if (cfg(priv)->lib->bt_rx_handler_setup) 1148 if (cfg(priv)->lib->bt_rx_handler_setup)
@@ -1164,25 +1162,7 @@ int iwl_rx_dispatch(struct iwl_op_mode *op_mode, struct iwl_rx_cmd_buffer *rxb,
1164 * even if the RX handler consumes the RXB we have 1162 * even if the RX handler consumes the RXB we have
1165 * access to it in the notification wait entry. 1163 * access to it in the notification wait entry.
1166 */ 1164 */
1167 if (!list_empty(&priv->shrd->notif_waits)) { 1165 iwl_notification_wait_notify(&priv->notif_wait, pkt);
1168 struct iwl_notification_wait *w;
1169
1170 spin_lock(&priv->shrd->notif_wait_lock);
1171 list_for_each_entry(w, &priv->shrd->notif_waits, list) {
1172 if (w->cmd != pkt->hdr.cmd)
1173 continue;
1174 IWL_DEBUG_RX(priv,
1175 "Notif: %s, 0x%02x - wake the callers up\n",
1176 get_cmd_string(pkt->hdr.cmd),
1177 pkt->hdr.cmd);
1178 w->triggered = true;
1179 if (w->fn)
1180 w->fn(priv, pkt, w->fn_data);
1181 }
1182 spin_unlock(&priv->shrd->notif_wait_lock);
1183
1184 wake_up_all(&priv->shrd->notif_waitq);
1185 }
1186 1166
1187 if (priv->pre_rx_handler && 1167 if (priv->pre_rx_handler &&
1188 priv->shrd->ucode_owner == IWL_OWNERSHIP_TM) 1168 priv->shrd->ucode_owner == IWL_OWNERSHIP_TM)
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
index e191d394cfa..9d955fa387e 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-rxon.c
@@ -60,9 +60,9 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
60 u8 old_dev_type = send->dev_type; 60 u8 old_dev_type = send->dev_type;
61 int ret; 61 int ret;
62 62
63 iwl_init_notification_wait(priv->shrd, &disable_wait, 63 iwl_init_notification_wait(&priv->notif_wait, &disable_wait,
64 REPLY_WIPAN_DEACTIVATION_COMPLETE, 64 REPLY_WIPAN_DEACTIVATION_COMPLETE,
65 NULL, NULL); 65 NULL, NULL);
66 66
67 send->filter_flags &= ~RXON_FILTER_ASSOC_MSK; 67 send->filter_flags &= ~RXON_FILTER_ASSOC_MSK;
68 send->dev_type = RXON_DEV_TYPE_P2P; 68 send->dev_type = RXON_DEV_TYPE_P2P;
@@ -74,9 +74,10 @@ static int iwlagn_disable_pan(struct iwl_priv *priv,
74 74
75 if (ret) { 75 if (ret) {
76 IWL_ERR(priv, "Error disabling PAN (%d)\n", ret); 76 IWL_ERR(priv, "Error disabling PAN (%d)\n", ret);
77 iwl_remove_notification(priv->shrd, &disable_wait); 77 iwl_remove_notification(&priv->notif_wait, &disable_wait);
78 } else { 78 } else {
79 ret = iwl_wait_notification(priv->shrd, &disable_wait, HZ); 79 ret = iwl_wait_notification(&priv->notif_wait,
80 &disable_wait, HZ);
80 if (ret) 81 if (ret)
81 IWL_ERR(priv, "Timed out waiting for PAN disable\n"); 82 IWL_ERR(priv, "Timed out waiting for PAN disable\n");
82 } 83 }
diff --git a/drivers/net/wireless/iwlwifi/iwl-core.c b/drivers/net/wireless/iwlwifi/iwl-core.c
index 2422eef6d15..5f0e07c0b50 100644
--- a/drivers/net/wireless/iwlwifi/iwl-core.c
+++ b/drivers/net/wireless/iwlwifi/iwl-core.c
@@ -845,7 +845,7 @@ static void iwlagn_fw_error(struct iwl_priv *priv, bool ondemand)
845 /* Cancel currently queued command. */ 845 /* Cancel currently queued command. */
846 clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status); 846 clear_bit(STATUS_HCMD_ACTIVE, &priv->shrd->status);
847 847
848 iwl_abort_notification_waits(priv->shrd); 848 iwl_abort_notification_waits(&priv->notif_wait);
849 849
850 /* Keep the restart process from trying to send host 850 /* Keep the restart process from trying to send host
851 * commands by clearing the ready bit */ 851 * commands by clearing the ready bit */
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 0c397fd635a..c57e605b26b 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -51,6 +51,7 @@
51#include "iwl-trans.h" 51#include "iwl-trans.h"
52#include "iwl-shared.h" 52#include "iwl-shared.h"
53#include "iwl-op-mode.h" 53#include "iwl-op-mode.h"
54#include "iwl-notif-wait.h"
54 55
55struct iwl_tx_queue; 56struct iwl_tx_queue;
56 57
@@ -739,6 +740,8 @@ struct iwl_priv {
739 struct iwl_rx_cmd_buffer *rxb, 740 struct iwl_rx_cmd_buffer *rxb,
740 struct iwl_device_cmd *cmd); 741 struct iwl_device_cmd *cmd);
741 742
743 struct iwl_notif_wait_data notif_wait;
744
742 struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS]; 745 struct ieee80211_supported_band bands[IEEE80211_NUM_BANDS];
743 746
744 /* spectrum measurement report caching */ 747 /* spectrum measurement report caching */
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
new file mode 100644
index 00000000000..88dc4a0f96b
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
@@ -0,0 +1,157 @@
1/******************************************************************************
2 *
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * GPL LICENSE SUMMARY
7 *
8 * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
22 * USA
23 *
24 * The full GNU General Public License is included in this distribution
25 * in the file called LICENSE.GPL.
26 *
27 * Contact Information:
28 * Intel Linux Wireless <ilw@linux.intel.com>
29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30 *
31 * BSD LICENSE
32 *
33 * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 *
40 * * Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * * Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in
44 * the documentation and/or other materials provided with the
45 * distribution.
46 * * Neither the name Intel Corporation nor the names of its
47 * contributors may be used to endorse or promote products derived
48 * from this software without specific prior written permission.
49 *
50 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
51 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
52 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
53 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
54 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
55 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
56 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
57 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
58 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
59 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
60 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
61 *
62 *****************************************************************************/
63#include <linux/sched.h>
64
65#include "iwl-notif-wait.h"
66
67
68void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
69{
70 spin_lock_init(&notif_wait->notif_wait_lock);
71 INIT_LIST_HEAD(&notif_wait->notif_waits);
72 init_waitqueue_head(&notif_wait->notif_waitq);
73}
74
75void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
76 struct iwl_rx_packet *pkt)
77{
78 if (!list_empty(&notif_wait->notif_waits)) {
79 struct iwl_notification_wait *w;
80
81 spin_lock(&notif_wait->notif_wait_lock);
82 list_for_each_entry(w, &notif_wait->notif_waits, list) {
83 if (w->cmd != pkt->hdr.cmd)
84 continue;
85 w->triggered = true;
86 if (w->fn)
87 w->fn(notif_wait, pkt, w->fn_data);
88 }
89 spin_unlock(&notif_wait->notif_wait_lock);
90
91 wake_up_all(&notif_wait->notif_waitq);
92 }
93}
94
95void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
96{
97 unsigned long flags;
98 struct iwl_notification_wait *wait_entry;
99
100 spin_lock_irqsave(&notif_wait->notif_wait_lock, flags);
101 list_for_each_entry(wait_entry, &notif_wait->notif_waits, list)
102 wait_entry->aborted = true;
103 spin_unlock_irqrestore(&notif_wait->notif_wait_lock, flags);
104
105 wake_up_all(&notif_wait->notif_waitq);
106}
107
108
109void
110iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
111 struct iwl_notification_wait *wait_entry,
112 u8 cmd,
113 void (*fn)(struct iwl_notif_wait_data *notif_wait,
114 struct iwl_rx_packet *pkt, void *data),
115 void *fn_data)
116{
117 wait_entry->fn = fn;
118 wait_entry->fn_data = fn_data;
119 wait_entry->cmd = cmd;
120 wait_entry->triggered = false;
121 wait_entry->aborted = false;
122
123 spin_lock_bh(&notif_wait->notif_wait_lock);
124 list_add(&wait_entry->list, &notif_wait->notif_waits);
125 spin_unlock_bh(&notif_wait->notif_wait_lock);
126}
127
128int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
129 struct iwl_notification_wait *wait_entry,
130 unsigned long timeout)
131{
132 int ret;
133
134 ret = wait_event_timeout(notif_wait->notif_waitq,
135 wait_entry->triggered || wait_entry->aborted,
136 timeout);
137
138 spin_lock_bh(&notif_wait->notif_wait_lock);
139 list_del(&wait_entry->list);
140 spin_unlock_bh(&notif_wait->notif_wait_lock);
141
142 if (wait_entry->aborted)
143 return -EIO;
144
145 /* return value is always >= 0 */
146 if (ret <= 0)
147 return -ETIMEDOUT;
148 return 0;
149}
150
151void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
152 struct iwl_notification_wait *wait_entry)
153{
154 spin_lock_bh(&notif_wait->notif_wait_lock);
155 list_del(&wait_entry->list);
156 spin_unlock_bh(&notif_wait->notif_wait_lock);
157}
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.h b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
new file mode 100644
index 00000000000..419f1ad6544
--- /dev/null
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.h
@@ -0,0 +1,130 @@
1/******************************************************************************
2 *
3 * This file is provided under a dual BSD/GPLv2 license. When using or
4 * redistributing this file, you may do so under either license.
5 *
6 * GPL LICENSE SUMMARY
7 *
8 * Copyright(c) 2007 - 2012 Intel Corporation. All rights reserved.
9 *
10 * This program is free software; you can redistribute it and/or modify
11 * it under the terms of version 2 of the GNU General Public License as
12 * published by the Free Software Foundation.
13 *
14 * This program is distributed in the hope that it will be useful, but
15 * WITHOUT ANY WARRANTY; without even the implied warranty of
16 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
17 * General Public License for more details.
18 *
19 * You should have received a copy of the GNU General Public License
20 * along with this program; if not, write to the Free Software
21 * Foundation, Inc., 51 Franklin Street, Fifth Floor, Boston, MA 02110,
22 * USA
23 *
24 * The full GNU General Public License is included in this distribution
25 * in the file called LICENSE.GPL.
26 *
27 * Contact Information:
28 * Intel Linux Wireless <ilw@linux.intel.com>
29 * Intel Corporation, 5200 N.E. Elam Young Parkway, Hillsboro, OR 97124-6497
30 *
31 * BSD LICENSE
32 *
33 * Copyright(c) 2005 - 2012 Intel Corporation. All rights reserved.
34 * All rights reserved.
35 *
36 * Redistribution and use in source and binary forms, with or without
37 * modification, are permitted provided that the following conditions
38 * are met:
39 *
40 * * Redistributions of source code must retain the above copyright
41 * notice, this list of conditions and the following disclaimer.
42 * * Redistributions in binary form must reproduce the above copyright
43 * notice, this list of conditions and the following disclaimer in
44 * distribution.
45 * * Neither the name Intel Corporation nor the names of its
46 * contributors may be used to endorse or promote products derived
47 * from this software without specific prior written permission.
48 *
49 * THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS
50 * "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
51 * LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
52 * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT
53 * OWNER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
54 * SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT
55 * LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR SERVICES; LOSS OF USE,
56 * DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY
57 * THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
58 * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE USE
59 * OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.
60 *
61 *****************************************************************************/
62#ifndef __iwl_notif_wait_h__
63#define __iwl_notif_wait_h__
64
65#include <linux/wait.h>
66
67/* TODO: remove later */
68#include "iwl-commands.h"
69
70struct iwl_notif_wait_data {
71 struct list_head notif_waits;
72 spinlock_t notif_wait_lock;
73 wait_queue_head_t notif_waitq;
74};
75
76/**
77 * struct iwl_notification_wait - notification wait entry
78 * @list: list head for global list
79 * @fn: function called with the notification
80 * @cmd: command ID
81 *
82 * This structure is not used directly, to wait for a
83 * notification declare it on the stack, and call
84 * iwlagn_init_notification_wait() with appropriate
85 * parameters. Then do whatever will cause the ucode
86 * to notify the driver, and to wait for that then
87 * call iwlagn_wait_notification().
88 *
89 * Each notification is one-shot. If at some point we
90 * need to support multi-shot notifications (which
91 * can't be allocated on the stack) we need to modify
92 * the code for them.
93 */
94struct iwl_notification_wait {
95 struct list_head list;
96
97 void (*fn)(struct iwl_notif_wait_data *notif_data,
98 struct iwl_rx_packet *pkt, void *data);
99 void *fn_data;
100
101 u8 cmd;
102 bool triggered, aborted;
103};
104
105
106/* caller functions */
107void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_data);
108void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_data,
109 struct iwl_rx_packet *pkt);
110void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data);
111
112/* user functions */
113void __acquires(wait_entry)
114iwl_init_notification_wait(struct iwl_notif_wait_data *notif_data,
115 struct iwl_notification_wait *wait_entry,
116 u8 cmd,
117 void (*fn)(struct iwl_notif_wait_data *notif_data,
118 struct iwl_rx_packet *pkt, void *data),
119 void *fn_data);
120
121int __must_check __releases(wait_entry)
122iwl_wait_notification(struct iwl_notif_wait_data *notif_data,
123 struct iwl_notification_wait *wait_entry,
124 unsigned long timeout);
125
126void __releases(wait_entry)
127iwl_remove_notification(struct iwl_notif_wait_data *notif_data,
128 struct iwl_notification_wait *wait_entry);
129
130#endif /* __iwl_notif_wait_h__ */
diff --git a/drivers/net/wireless/iwlwifi/iwl-shared.h b/drivers/net/wireless/iwlwifi/iwl-shared.h
index 5a67fa14174..8ffc7607912 100644
--- a/drivers/net/wireless/iwlwifi/iwl-shared.h
+++ b/drivers/net/wireless/iwlwifi/iwl-shared.h
@@ -212,35 +212,6 @@ enum iwl_ucode_type {
212}; 212};
213 213
214/** 214/**
215 * struct iwl_notification_wait - notification wait entry
216 * @list: list head for global list
217 * @fn: function called with the notification
218 * @cmd: command ID
219 *
220 * This structure is not used directly, to wait for a
221 * notification declare it on the stack, and call
222 * iwlagn_init_notification_wait() with appropriate
223 * parameters. Then do whatever will cause the ucode
224 * to notify the driver, and to wait for that then
225 * call iwlagn_wait_notification().
226 *
227 * Each notification is one-shot. If at some point we
228 * need to support multi-shot notifications (which
229 * can't be allocated on the stack) we need to modify
230 * the code for them.
231 */
232struct iwl_notification_wait {
233 struct list_head list;
234
235 void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt,
236 void *data);
237 void *fn_data;
238
239 u8 cmd;
240 bool triggered, aborted;
241};
242
243/**
244 * enum iwl_pa_type - Power Amplifier type 215 * enum iwl_pa_type - Power Amplifier type
245 * @IWL_PA_SYSTEM: based on uCode configuration 216 * @IWL_PA_SYSTEM: based on uCode configuration
246 * @IWL_PA_INTERNAL: use Internal only 217 * @IWL_PA_INTERNAL: use Internal only
@@ -400,9 +371,6 @@ struct iwl_cfg {
400 * @wait_command_queue: the wait_queue for SYNC host command nad uCode load 371 * @wait_command_queue: the wait_queue for SYNC host command nad uCode load
401 * @eeprom: pointer to the eeprom/OTP image 372 * @eeprom: pointer to the eeprom/OTP image
402 * @ucode_type: indicator of loaded ucode image 373 * @ucode_type: indicator of loaded ucode image
403 * @notif_waits: things waiting for notification
404 * @notif_wait_lock: lock protecting notification
405 * @notif_waitq: head of notification wait queue
406 * @device_pointers: pointers to ucode event tables 374 * @device_pointers: pointers to ucode event tables
407 */ 375 */
408struct iwl_shared { 376struct iwl_shared {
@@ -428,11 +396,6 @@ struct iwl_shared {
428 /* ucode related variables */ 396 /* ucode related variables */
429 enum iwl_ucode_type ucode_type; 397 enum iwl_ucode_type ucode_type;
430 398
431 /* notification wait support */
432 struct list_head notif_waits;
433 spinlock_t notif_wait_lock;
434 wait_queue_head_t notif_waitq;
435
436 struct { 399 struct {
437 u32 error_event_table; 400 u32 error_event_table;
438 u32 log_event_table; 401 u32 log_event_table;
@@ -462,24 +425,6 @@ int iwlagn_hw_valid_rtc_data_addr(u32 addr);
462void iwl_nic_config(struct iwl_priv *priv); 425void iwl_nic_config(struct iwl_priv *priv);
463const char *get_cmd_string(u8 cmd); 426const char *get_cmd_string(u8 cmd);
464 427
465/* notification wait support */
466void iwl_abort_notification_waits(struct iwl_shared *shrd);
467void __acquires(wait_entry)
468iwl_init_notification_wait(struct iwl_shared *shrd,
469 struct iwl_notification_wait *wait_entry,
470 u8 cmd,
471 void (*fn)(struct iwl_priv *priv,
472 struct iwl_rx_packet *pkt,
473 void *data),
474 void *fn_data);
475int __must_check __releases(wait_entry)
476iwl_wait_notification(struct iwl_shared *shrd,
477 struct iwl_notification_wait *wait_entry,
478 unsigned long timeout);
479void __releases(wait_entry)
480iwl_remove_notification(struct iwl_shared *shrd,
481 struct iwl_notification_wait *wait_entry);
482
483#define IWL_CMD(x) case x: return #x 428#define IWL_CMD(x) case x: return #x
484 429
485/***************************************************** 430/*****************************************************
diff --git a/drivers/net/wireless/iwlwifi/iwl-testmode.c b/drivers/net/wireless/iwlwifi/iwl-testmode.c
index 095d71dc99c..cc049d22151 100644
--- a/drivers/net/wireless/iwlwifi/iwl-testmode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-testmode.c
@@ -418,23 +418,23 @@ static int iwl_testmode_cfg_init_calib(struct iwl_priv *priv)
418 struct iwl_notification_wait calib_wait; 418 struct iwl_notification_wait calib_wait;
419 int ret; 419 int ret;
420 420
421 iwl_init_notification_wait(priv->shrd, &calib_wait, 421 iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
422 CALIBRATION_COMPLETE_NOTIFICATION, 422 CALIBRATION_COMPLETE_NOTIFICATION,
423 NULL, NULL); 423 NULL, NULL);
424 ret = iwl_init_alive_start(priv); 424 ret = iwl_init_alive_start(priv);
425 if (ret) { 425 if (ret) {
426 IWL_ERR(priv, "Fail init calibration: %d\n", ret); 426 IWL_ERR(priv, "Fail init calibration: %d\n", ret);
427 goto cfg_init_calib_error; 427 goto cfg_init_calib_error;
428 } 428 }
429 429
430 ret = iwl_wait_notification(priv->shrd, &calib_wait, 2 * HZ); 430 ret = iwl_wait_notification(&priv->notif_wait, &calib_wait, 2 * HZ);
431 if (ret) 431 if (ret)
432 IWL_ERR(priv, "Error detecting" 432 IWL_ERR(priv, "Error detecting"
433 " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret); 433 " CALIBRATION_COMPLETE_NOTIFICATION: %d\n", ret);
434 return ret; 434 return ret;
435 435
436cfg_init_calib_error: 436cfg_init_calib_error:
437 iwl_remove_notification(priv->shrd, &calib_wait); 437 iwl_remove_notification(&priv->notif_wait, &calib_wait);
438 return ret; 438 return ret;
439} 439}
440 440
diff --git a/drivers/net/wireless/iwlwifi/iwl-ucode.c b/drivers/net/wireless/iwlwifi/iwl-ucode.c
index 686d456d226..4d34327f942 100644
--- a/drivers/net/wireless/iwlwifi/iwl-ucode.c
+++ b/drivers/net/wireless/iwlwifi/iwl-ucode.c
@@ -29,7 +29,6 @@
29 29
30#include <linux/kernel.h> 30#include <linux/kernel.h>
31#include <linux/init.h> 31#include <linux/init.h>
32#include <linux/sched.h>
33 32
34#include "iwl-dev.h" 33#include "iwl-dev.h"
35#include "iwl-core.h" 34#include "iwl-core.h"
@@ -434,10 +433,12 @@ struct iwl_alive_data {
434 u8 subtype; 433 u8 subtype;
435}; 434};
436 435
437static void iwl_alive_fn(struct iwl_priv *priv, 436static void iwl_alive_fn(struct iwl_notif_wait_data *notif_wait,
438 struct iwl_rx_packet *pkt, 437 struct iwl_rx_packet *pkt,
439 void *data) 438 void *data)
440{ 439{
440 struct iwl_priv *priv =
441 container_of(notif_wait, struct iwl_priv, notif_wait);
441 struct iwl_alive_data *alive_data = data; 442 struct iwl_alive_data *alive_data = data;
442 struct iwl_alive_resp *palive; 443 struct iwl_alive_resp *palive;
443 444
@@ -457,70 +458,6 @@ static void iwl_alive_fn(struct iwl_priv *priv,
457 alive_data->valid = palive->is_valid == UCODE_VALID_OK; 458 alive_data->valid = palive->is_valid == UCODE_VALID_OK;
458} 459}
459 460
460/* notification wait support */
461void iwl_init_notification_wait(struct iwl_shared *shrd,
462 struct iwl_notification_wait *wait_entry,
463 u8 cmd,
464 void (*fn)(struct iwl_priv *priv,
465 struct iwl_rx_packet *pkt,
466 void *data),
467 void *fn_data)
468{
469 wait_entry->fn = fn;
470 wait_entry->fn_data = fn_data;
471 wait_entry->cmd = cmd;
472 wait_entry->triggered = false;
473 wait_entry->aborted = false;
474
475 spin_lock_bh(&shrd->notif_wait_lock);
476 list_add(&wait_entry->list, &shrd->notif_waits);
477 spin_unlock_bh(&shrd->notif_wait_lock);
478}
479
480int iwl_wait_notification(struct iwl_shared *shrd,
481 struct iwl_notification_wait *wait_entry,
482 unsigned long timeout)
483{
484 int ret;
485
486 ret = wait_event_timeout(shrd->notif_waitq,
487 wait_entry->triggered || wait_entry->aborted,
488 timeout);
489
490 spin_lock_bh(&shrd->notif_wait_lock);
491 list_del(&wait_entry->list);
492 spin_unlock_bh(&shrd->notif_wait_lock);
493
494 if (wait_entry->aborted)
495 return -EIO;
496
497 /* return value is always >= 0 */
498 if (ret <= 0)
499 return -ETIMEDOUT;
500 return 0;
501}
502
503void iwl_remove_notification(struct iwl_shared *shrd,
504 struct iwl_notification_wait *wait_entry)
505{
506 spin_lock_bh(&shrd->notif_wait_lock);
507 list_del(&wait_entry->list);
508 spin_unlock_bh(&shrd->notif_wait_lock);
509}
510
511void iwl_abort_notification_waits(struct iwl_shared *shrd)
512{
513 unsigned long flags;
514 struct iwl_notification_wait *wait_entry;
515
516 spin_lock_irqsave(&shrd->notif_wait_lock, flags);
517 list_for_each_entry(wait_entry, &shrd->notif_waits, list)
518 wait_entry->aborted = true;
519 spin_unlock_irqrestore(&shrd->notif_wait_lock, flags);
520
521 wake_up_all(&shrd->notif_waitq);
522}
523
524#define UCODE_ALIVE_TIMEOUT HZ 461#define UCODE_ALIVE_TIMEOUT HZ
525#define UCODE_CALIB_TIMEOUT (2*HZ) 462#define UCODE_CALIB_TIMEOUT (2*HZ)
526 463
@@ -540,13 +477,13 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
540 if (!fw) 477 if (!fw)
541 return -EINVAL; 478 return -EINVAL;
542 479
543 iwl_init_notification_wait(priv->shrd, &alive_wait, REPLY_ALIVE, 480 iwl_init_notification_wait(&priv->notif_wait, &alive_wait, REPLY_ALIVE,
544 iwl_alive_fn, &alive_data); 481 iwl_alive_fn, &alive_data);
545 482
546 ret = iwl_trans_start_fw(trans(priv), fw); 483 ret = iwl_trans_start_fw(trans(priv), fw);
547 if (ret) { 484 if (ret) {
548 priv->shrd->ucode_type = old_type; 485 priv->shrd->ucode_type = old_type;
549 iwl_remove_notification(priv->shrd, &alive_wait); 486 iwl_remove_notification(&priv->notif_wait, &alive_wait);
550 return ret; 487 return ret;
551 } 488 }
552 489
@@ -554,7 +491,7 @@ int iwl_load_ucode_wait_alive(struct iwl_priv *priv,
554 * Some things may run in the background now, but we 491 * Some things may run in the background now, but we
555 * just wait for the ALIVE notification here. 492 * just wait for the ALIVE notification here.
556 */ 493 */
557 ret = iwl_wait_notification(priv->shrd, &alive_wait, 494 ret = iwl_wait_notification(&priv->notif_wait, &alive_wait,
558 UCODE_ALIVE_TIMEOUT); 495 UCODE_ALIVE_TIMEOUT);
559 if (ret) { 496 if (ret) {
560 priv->shrd->ucode_type = old_type; 497 priv->shrd->ucode_type = old_type;
@@ -608,7 +545,7 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
608 if (priv->shrd->ucode_type != IWL_UCODE_NONE) 545 if (priv->shrd->ucode_type != IWL_UCODE_NONE)
609 return 0; 546 return 0;
610 547
611 iwl_init_notification_wait(priv->shrd, &calib_wait, 548 iwl_init_notification_wait(&priv->notif_wait, &calib_wait,
612 CALIBRATION_COMPLETE_NOTIFICATION, 549 CALIBRATION_COMPLETE_NOTIFICATION,
613 NULL, NULL); 550 NULL, NULL);
614 551
@@ -625,13 +562,13 @@ int iwl_run_init_ucode(struct iwl_priv *priv)
625 * Some things may run in the background now, but we 562 * Some things may run in the background now, but we
626 * just wait for the calibration complete notification. 563 * just wait for the calibration complete notification.
627 */ 564 */
628 ret = iwl_wait_notification(priv->shrd, &calib_wait, 565 ret = iwl_wait_notification(&priv->notif_wait, &calib_wait,
629 UCODE_CALIB_TIMEOUT); 566 UCODE_CALIB_TIMEOUT);
630 567
631 goto out; 568 goto out;
632 569
633 error: 570 error:
634 iwl_remove_notification(priv->shrd, &calib_wait); 571 iwl_remove_notification(&priv->notif_wait, &calib_wait);
635 out: 572 out:
636 /* Whatever happened, stop the device */ 573 /* Whatever happened, stop the device */
637 iwl_trans_stop_device(trans(priv)); 574 iwl_trans_stop_device(trans(priv));