aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
authorJohannes Berg <johannes.berg@intel.com>2011-01-04 19:22:00 -0500
committerJohn W. Linville <linville@tuxdriver.com>2011-01-21 15:32:20 -0500
commit7194207ceea7a54c846e0865d2459f4887fe1e0d (patch)
treeeff27d7461dc336187a3765fd79e0daba7d8fc49
parentf945f1087f1fe20f9c626daa175b677736fc614d (diff)
iwlagn: add support for waiting for notifications
In order to implement waiting for notifications, add a structure that captures the information, and a list of such structures that will be traversed when a command is received from the ucode. Use sparse checking to make sure calls to the prepare/wait/cancel functions are always nested correctly. 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>
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn-lib.c46
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.c21
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-agn.h15
-rw-r--r--drivers/net/wireless/iwlwifi/iwl-dev.h33
4 files changed, 115 insertions, 0 deletions
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
index 3dee87e8f55d..29dcda0bde65 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn-lib.c
@@ -473,6 +473,11 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
473 priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] = 473 priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
474 iwlagn_rx_calib_complete; 474 iwlagn_rx_calib_complete;
475 priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx; 475 priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
476
477 /* set up notification wait support */
478 spin_lock_init(&priv->_agn.notif_wait_lock);
479 INIT_LIST_HEAD(&priv->_agn.notif_waits);
480 init_waitqueue_head(&priv->_agn.notif_waitq);
476} 481}
477 482
478void iwlagn_setup_deferred_work(struct iwl_priv *priv) 483void iwlagn_setup_deferred_work(struct iwl_priv *priv)
@@ -2389,3 +2394,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
2389 } 2394 }
2390 return 0; 2395 return 0;
2391} 2396}
2397
2398/* notification wait support */
2399void iwlagn_init_notification_wait(struct iwl_priv *priv,
2400 struct iwl_notification_wait *wait_entry,
2401 void (*fn)(struct iwl_priv *priv,
2402 struct iwl_rx_packet *pkt),
2403 u8 cmd)
2404{
2405 wait_entry->fn = fn;
2406 wait_entry->cmd = cmd;
2407 wait_entry->triggered = false;
2408
2409 spin_lock_bh(&priv->_agn.notif_wait_lock);
2410 list_add(&wait_entry->list, &priv->_agn.notif_waits);
2411 spin_unlock_bh(&priv->_agn.notif_wait_lock);
2412}
2413
2414signed long iwlagn_wait_notification(struct iwl_priv *priv,
2415 struct iwl_notification_wait *wait_entry,
2416 unsigned long timeout)
2417{
2418 int ret;
2419
2420 ret = wait_event_timeout(priv->_agn.notif_waitq,
2421 &wait_entry->triggered,
2422 timeout);
2423
2424 spin_lock_bh(&priv->_agn.notif_wait_lock);
2425 list_del(&wait_entry->list);
2426 spin_unlock_bh(&priv->_agn.notif_wait_lock);
2427
2428 return ret;
2429}
2430
2431void iwlagn_remove_notification(struct iwl_priv *priv,
2432 struct iwl_notification_wait *wait_entry)
2433{
2434 spin_lock_bh(&priv->_agn.notif_wait_lock);
2435 list_del(&wait_entry->list);
2436 spin_unlock_bh(&priv->_agn.notif_wait_lock);
2437}
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.c b/drivers/net/wireless/iwlwifi/iwl-agn.c
index 624f174f8664..97657d04aa68 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.c
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.c
@@ -910,6 +910,27 @@ static void iwl_rx_handle(struct iwl_priv *priv)
910 (pkt->hdr.cmd != STATISTICS_NOTIFICATION) && 910 (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
911 (pkt->hdr.cmd != REPLY_TX); 911 (pkt->hdr.cmd != REPLY_TX);
912 912
913 /*
914 * Do the notification wait before RX handlers so
915 * even if the RX handler consumes the RXB we have
916 * access to it in the notification wait entry.
917 */
918 if (!list_empty(&priv->_agn.notif_waits)) {
919 struct iwl_notification_wait *w;
920
921 spin_lock(&priv->_agn.notif_wait_lock);
922 list_for_each_entry(w, &priv->_agn.notif_waits, list) {
923 if (w->cmd == pkt->hdr.cmd) {
924 w->triggered = true;
925 if (w->fn)
926 w->fn(priv, pkt);
927 }
928 }
929 spin_unlock(&priv->_agn.notif_wait_lock);
930
931 wake_up_all(&priv->_agn.notif_waitq);
932 }
933
913 /* Based on type of command response or notification, 934 /* Based on type of command response or notification,
914 * handle those that need handling via function in 935 * handle those that need handling via function in
915 * rx_handlers table. See iwl_setup_rx_handlers() */ 936 * rx_handlers table. See iwl_setup_rx_handlers() */
diff --git a/drivers/net/wireless/iwlwifi/iwl-agn.h b/drivers/net/wireless/iwlwifi/iwl-agn.h
index c30dc4f7a619..74d72ff24d05 100644
--- a/drivers/net/wireless/iwlwifi/iwl-agn.h
+++ b/drivers/net/wireless/iwlwifi/iwl-agn.h
@@ -329,6 +329,21 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
329int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv); 329int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
330void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv); 330void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
331 331
332/* notification wait support */
333void __acquires(wait_entry)
334iwlagn_init_notification_wait(struct iwl_priv *priv,
335 struct iwl_notification_wait *wait_entry,
336 void (*fn)(struct iwl_priv *priv,
337 struct iwl_rx_packet *pkt),
338 u8 cmd);
339signed long __releases(wait_entry)
340iwlagn_wait_notification(struct iwl_priv *priv,
341 struct iwl_notification_wait *wait_entry,
342 unsigned long timeout);
343void __releases(wait_entry)
344iwlagn_remove_notification(struct iwl_priv *priv,
345 struct iwl_notification_wait *wait_entry);
346
332/* mac80211 handlers (for 4965) */ 347/* mac80211 handlers (for 4965) */
333int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb); 348int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
334int iwlagn_mac_start(struct ieee80211_hw *hw); 349int iwlagn_mac_start(struct ieee80211_hw *hw);
diff --git a/drivers/net/wireless/iwlwifi/iwl-dev.h b/drivers/net/wireless/iwlwifi/iwl-dev.h
index 8dda67850af4..2ec680bb8f6d 100644
--- a/drivers/net/wireless/iwlwifi/iwl-dev.h
+++ b/drivers/net/wireless/iwlwifi/iwl-dev.h
@@ -34,6 +34,7 @@
34 34
35#include <linux/pci.h> /* for struct pci_device_id */ 35#include <linux/pci.h> /* for struct pci_device_id */
36#include <linux/kernel.h> 36#include <linux/kernel.h>
37#include <linux/wait.h>
37#include <net/ieee80211_radiotap.h> 38#include <net/ieee80211_radiotap.h>
38 39
39#include "iwl-eeprom.h" 40#include "iwl-eeprom.h"
@@ -1139,6 +1140,33 @@ struct iwl_force_reset {
1139 */ 1140 */
1140#define IWLAGN_EXT_BEACON_TIME_POS 22 1141#define IWLAGN_EXT_BEACON_TIME_POS 22
1141 1142
1143/**
1144 * struct iwl_notification_wait - notification wait entry
1145 * @list: list head for global list
1146 * @fn: function called with the notification
1147 * @cmd: command ID
1148 *
1149 * This structure is not used directly, to wait for a
1150 * notification declare it on the stack, and call
1151 * iwlagn_init_notification_wait() with appropriate
1152 * parameters. Then do whatever will cause the ucode
1153 * to notify the driver, and to wait for that then
1154 * call iwlagn_wait_notification().
1155 *
1156 * Each notification is one-shot. If at some point we
1157 * need to support multi-shot notifications (which
1158 * can't be allocated on the stack) we need to modify
1159 * the code for them.
1160 */
1161struct iwl_notification_wait {
1162 struct list_head list;
1163
1164 void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt);
1165
1166 u8 cmd;
1167 bool triggered;
1168};
1169
1142enum iwl_rxon_context_id { 1170enum iwl_rxon_context_id {
1143 IWL_RXON_CTX_BSS, 1171 IWL_RXON_CTX_BSS,
1144 IWL_RXON_CTX_PAN, 1172 IWL_RXON_CTX_PAN,
@@ -1463,6 +1491,11 @@ struct iwl_priv {
1463 struct iwl_bt_notif_statistics delta_statistics_bt; 1491 struct iwl_bt_notif_statistics delta_statistics_bt;
1464 struct iwl_bt_notif_statistics max_delta_bt; 1492 struct iwl_bt_notif_statistics max_delta_bt;
1465#endif 1493#endif
1494
1495 /* notification wait support */
1496 struct list_head notif_waits;
1497 spinlock_t notif_wait_lock;
1498 wait_queue_head_t notif_waitq;
1466 } _agn; 1499 } _agn;
1467#endif 1500#endif
1468 }; 1501 };