mirror of
https://github.com/torvalds/linux.git
synced 2024-12-30 06:41:43 +00:00
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>
This commit is contained in:
parent
f945f1087f
commit
7194207cee
@ -473,6 +473,11 @@ void iwlagn_rx_handler_setup(struct iwl_priv *priv)
|
||||
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)
|
||||
@ -2389,3 +2394,44 @@ int iwl_dump_fh(struct iwl_priv *priv, char **buf, bool display)
|
||||
}
|
||||
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);
|
||||
}
|
||||
|
@ -910,6 +910,27 @@ static void iwl_rx_handle(struct iwl_priv *priv)
|
||||
(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() */
|
||||
|
@ -329,6 +329,21 @@ void iwl_eeprom_get_mac(const struct iwl_priv *priv, u8 *mac);
|
||||
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);
|
||||
|
@ -34,6 +34,7 @@
|
||||
|
||||
#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"
|
||||
@ -1139,6 +1140,33 @@ struct iwl_force_reset {
|
||||
*/
|
||||
#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,
|
||||
@ -1463,6 +1491,11 @@ struct iwl_priv {
|
||||
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
|
||||
};
|
||||
|
Loading…
Reference in New Issue
Block a user