aboutsummaryrefslogtreecommitdiffstats
path: root/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2012-03-15 16:26:44 -0400
committerJohn W. Linville <linville@tuxdriver.com>2012-04-09 16:37:15 -0400
commitdb662d478695a967b9d0a4c9893278e797b73f6c (patch)
tree3a5cf5c45c1bf241eb5dbf354c5122d53c55a14a /drivers/net/wireless/iwlwifi/iwl-notif-wait.c
parent0c19744c344cf1bfda04f681ff4e1e46455577bd (diff)
iwlwifi: extend notification wait
Sometimes, for example when we ask the uCode for calibration, we wait for the "complete" response while we also need the results that are sent in other, interim, notifications. Currently we handle this by installing an RX handler globally, but that isn't needed as this is the only time we want to use these notifications. So in order to be able to simplify at least future code that does the same, extend the notification wait framework to allow you to wait for multiple commands and decide based on the command whether the wait finished. While at it, also fix a race that can then become relevant -- if the wait function has returned true once it shouldn't be called again, today this can happen due to races between the triggering and the wakeup. 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/iwl-notif-wait.c')
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-notif-wait.c44
1 files changed, 36 insertions, 8 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
index 88dc4a0f96b4..0066b899fe5c 100644
--- a/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
+++ b/drivers/net/wireless/iwlwifi/iwl-notif-wait.c
@@ -75,21 +75,45 @@ void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
75void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait, 75void iwl_notification_wait_notify(struct iwl_notif_wait_data *notif_wait,
76 struct iwl_rx_packet *pkt) 76 struct iwl_rx_packet *pkt)
77{ 77{
78 bool triggered = false;
79
78 if (!list_empty(&notif_wait->notif_waits)) { 80 if (!list_empty(&notif_wait->notif_waits)) {
79 struct iwl_notification_wait *w; 81 struct iwl_notification_wait *w;
80 82
81 spin_lock(&notif_wait->notif_wait_lock); 83 spin_lock(&notif_wait->notif_wait_lock);
82 list_for_each_entry(w, &notif_wait->notif_waits, list) { 84 list_for_each_entry(w, &notif_wait->notif_waits, list) {
83 if (w->cmd != pkt->hdr.cmd) 85 int i;
86 bool found = false;
87
88 /*
89 * If it already finished (triggered) or has been
90 * aborted then don't evaluate it again to avoid races,
91 * Otherwise the function could be called again even
92 * though it returned true before
93 */
94 if (w->triggered || w->aborted)
95 continue;
96
97 for (i = 0; i < w->n_cmds; i++) {
98 if (w->cmds[i] == pkt->hdr.cmd) {
99 found = true;
100 break;
101 }
102 }
103 if (!found)
84 continue; 104 continue;
85 w->triggered = true; 105
86 if (w->fn) 106 if (!w->fn || w->fn(notif_wait, pkt, w->fn_data)) {
87 w->fn(notif_wait, pkt, w->fn_data); 107 w->triggered = true;
108 triggered = true;
109 }
88 } 110 }
89 spin_unlock(&notif_wait->notif_wait_lock); 111 spin_unlock(&notif_wait->notif_wait_lock);
90 112
91 wake_up_all(&notif_wait->notif_waitq);
92 } 113 }
114
115 if (triggered)
116 wake_up_all(&notif_wait->notif_waitq);
93} 117}
94 118
95void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait) 119void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
@@ -109,14 +133,18 @@ void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
109void 133void
110iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait, 134iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
111 struct iwl_notification_wait *wait_entry, 135 struct iwl_notification_wait *wait_entry,
112 u8 cmd, 136 const u8 *cmds, int n_cmds,
113 void (*fn)(struct iwl_notif_wait_data *notif_wait, 137 bool (*fn)(struct iwl_notif_wait_data *notif_wait,
114 struct iwl_rx_packet *pkt, void *data), 138 struct iwl_rx_packet *pkt, void *data),
115 void *fn_data) 139 void *fn_data)
116{ 140{
141 if (WARN_ON(n_cmds > MAX_NOTIF_CMDS))
142 n_cmds = MAX_NOTIF_CMDS;
143
117 wait_entry->fn = fn; 144 wait_entry->fn = fn;
118 wait_entry->fn_data = fn_data; 145 wait_entry->fn_data = fn_data;
119 wait_entry->cmd = cmd; 146 wait_entry->n_cmds = n_cmds;
147 memcpy(wait_entry->cmds, cmds, n_cmds);
120 wait_entry->triggered = false; 148 wait_entry->triggered = false;
121 wait_entry->aborted = false; 149 wait_entry->aborted = false;
122 150