priv->rx_handlers[CALIBRATION_COMPLETE_NOTIFICATION] =
                                        iwlagn_rx_calib_complete;
        priv->rx_handlers[REPLY_TX] = iwlagn_rx_reply_tx;
+
+       /* set up notification wait support */
+       spin_lock_init(&priv->_agn.notif_wait_lock);
+       INIT_LIST_HEAD(&priv->_agn.notif_waits);
+       init_waitqueue_head(&priv->_agn.notif_waitq);
 }
 
 void iwlagn_setup_deferred_work(struct iwl_priv *priv)
        }
        return 0;
 }
+
+/* notification wait support */
+void iwlagn_init_notification_wait(struct iwl_priv *priv,
+                                  struct iwl_notification_wait *wait_entry,
+                                  void (*fn)(struct iwl_priv *priv,
+                                             struct iwl_rx_packet *pkt),
+                                  u8 cmd)
+{
+       wait_entry->fn = fn;
+       wait_entry->cmd = cmd;
+       wait_entry->triggered = false;
+
+       spin_lock_bh(&priv->_agn.notif_wait_lock);
+       list_add(&wait_entry->list, &priv->_agn.notif_waits);
+       spin_unlock_bh(&priv->_agn.notif_wait_lock);
+}
+
+signed long iwlagn_wait_notification(struct iwl_priv *priv,
+                                    struct iwl_notification_wait *wait_entry,
+                                    unsigned long timeout)
+{
+       int ret;
+
+       ret = wait_event_timeout(priv->_agn.notif_waitq,
+                                &wait_entry->triggered,
+                                timeout);
+
+       spin_lock_bh(&priv->_agn.notif_wait_lock);
+       list_del(&wait_entry->list);
+       spin_unlock_bh(&priv->_agn.notif_wait_lock);
+
+       return ret;
+}
+
+void iwlagn_remove_notification(struct iwl_priv *priv,
+                               struct iwl_notification_wait *wait_entry)
+{
+       spin_lock_bh(&priv->_agn.notif_wait_lock);
+       list_del(&wait_entry->list);
+       spin_unlock_bh(&priv->_agn.notif_wait_lock);
+}
 
                        (pkt->hdr.cmd != STATISTICS_NOTIFICATION) &&
                        (pkt->hdr.cmd != REPLY_TX);
 
+               /*
+                * Do the notification wait before RX handlers so
+                * even if the RX handler consumes the RXB we have
+                * access to it in the notification wait entry.
+                */
+               if (!list_empty(&priv->_agn.notif_waits)) {
+                       struct iwl_notification_wait *w;
+
+                       spin_lock(&priv->_agn.notif_wait_lock);
+                       list_for_each_entry(w, &priv->_agn.notif_waits, list) {
+                               if (w->cmd == pkt->hdr.cmd) {
+                                       w->triggered = true;
+                                       if (w->fn)
+                                               w->fn(priv, pkt);
+                               }
+                       }
+                       spin_unlock(&priv->_agn.notif_wait_lock);
+
+                       wake_up_all(&priv->_agn.notif_waitq);
+               }
+
                /* Based on type of command response or notification,
                 *   handle those that need handling via function in
                 *   rx_handlers table.  See iwl_setup_rx_handlers() */
 
 int iwlcore_eeprom_acquire_semaphore(struct iwl_priv *priv);
 void iwlcore_eeprom_release_semaphore(struct iwl_priv *priv);
 
+/* notification wait support */
+void __acquires(wait_entry)
+iwlagn_init_notification_wait(struct iwl_priv *priv,
+                             struct iwl_notification_wait *wait_entry,
+                             void (*fn)(struct iwl_priv *priv,
+                                        struct iwl_rx_packet *pkt),
+                             u8 cmd);
+signed long __releases(wait_entry)
+iwlagn_wait_notification(struct iwl_priv *priv,
+                        struct iwl_notification_wait *wait_entry,
+                        unsigned long timeout);
+void __releases(wait_entry)
+iwlagn_remove_notification(struct iwl_priv *priv,
+                          struct iwl_notification_wait *wait_entry);
+
 /* mac80211 handlers (for 4965) */
 int iwlagn_mac_tx(struct ieee80211_hw *hw, struct sk_buff *skb);
 int iwlagn_mac_start(struct ieee80211_hw *hw);
 
 
 #include <linux/pci.h> /* for struct pci_device_id */
 #include <linux/kernel.h>
+#include <linux/wait.h>
 #include <net/ieee80211_radiotap.h>
 
 #include "iwl-eeprom.h"
  */
 #define IWLAGN_EXT_BEACON_TIME_POS     22
 
+/**
+ * struct iwl_notification_wait - notification wait entry
+ * @list: list head for global list
+ * @fn: function called with the notification
+ * @cmd: command ID
+ *
+ * This structure is not used directly, to wait for a
+ * notification declare it on the stack, and call
+ * iwlagn_init_notification_wait() with appropriate
+ * parameters. Then do whatever will cause the ucode
+ * to notify the driver, and to wait for that then
+ * call iwlagn_wait_notification().
+ *
+ * Each notification is one-shot. If at some point we
+ * need to support multi-shot notifications (which
+ * can't be allocated on the stack) we need to modify
+ * the code for them.
+ */
+struct iwl_notification_wait {
+       struct list_head list;
+
+       void (*fn)(struct iwl_priv *priv, struct iwl_rx_packet *pkt);
+
+       u8 cmd;
+       bool triggered;
+};
+
 enum iwl_rxon_context_id {
        IWL_RXON_CTX_BSS,
        IWL_RXON_CTX_PAN,
                        struct iwl_bt_notif_statistics delta_statistics_bt;
                        struct iwl_bt_notif_statistics max_delta_bt;
 #endif
+
+                       /* notification wait support */
+                       struct list_head notif_waits;
+                       spinlock_t notif_wait_lock;
+                       wait_queue_head_t notif_waitq;
                } _agn;
 #endif
        };