0001
0002
0003
0004
0005
0006 #include <linux/sched.h>
0007 #include <linux/export.h>
0008
0009 #include "iwl-drv.h"
0010 #include "notif-wait.h"
0011
0012
0013 void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)
0014 {
0015 spin_lock_init(¬if_wait->notif_wait_lock);
0016 INIT_LIST_HEAD(¬if_wait->notif_waits);
0017 init_waitqueue_head(¬if_wait->notif_waitq);
0018 }
0019 IWL_EXPORT_SYMBOL(iwl_notification_wait_init);
0020
0021 bool iwl_notification_wait(struct iwl_notif_wait_data *notif_wait,
0022 struct iwl_rx_packet *pkt)
0023 {
0024 bool triggered = false;
0025
0026 if (!list_empty(¬if_wait->notif_waits)) {
0027 struct iwl_notification_wait *w;
0028
0029 spin_lock_bh(¬if_wait->notif_wait_lock);
0030 list_for_each_entry(w, ¬if_wait->notif_waits, list) {
0031 int i;
0032 bool found = false;
0033
0034
0035
0036
0037
0038
0039
0040 if (w->triggered || w->aborted)
0041 continue;
0042
0043 for (i = 0; i < w->n_cmds; i++) {
0044 u16 rec_id = WIDE_ID(pkt->hdr.group_id,
0045 pkt->hdr.cmd);
0046
0047 if (w->cmds[i] == rec_id ||
0048 (!iwl_cmd_groupid(w->cmds[i]) &&
0049 DEF_ID(w->cmds[i]) == rec_id)) {
0050 found = true;
0051 break;
0052 }
0053 }
0054 if (!found)
0055 continue;
0056
0057 if (!w->fn || w->fn(notif_wait, pkt, w->fn_data)) {
0058 w->triggered = true;
0059 triggered = true;
0060 }
0061 }
0062 spin_unlock_bh(¬if_wait->notif_wait_lock);
0063 }
0064
0065 return triggered;
0066 }
0067 IWL_EXPORT_SYMBOL(iwl_notification_wait);
0068
0069 void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)
0070 {
0071 struct iwl_notification_wait *wait_entry;
0072
0073 spin_lock_bh(¬if_wait->notif_wait_lock);
0074 list_for_each_entry(wait_entry, ¬if_wait->notif_waits, list)
0075 wait_entry->aborted = true;
0076 spin_unlock_bh(¬if_wait->notif_wait_lock);
0077
0078 wake_up_all(¬if_wait->notif_waitq);
0079 }
0080 IWL_EXPORT_SYMBOL(iwl_abort_notification_waits);
0081
0082 void
0083 iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,
0084 struct iwl_notification_wait *wait_entry,
0085 const u16 *cmds, int n_cmds,
0086 bool (*fn)(struct iwl_notif_wait_data *notif_wait,
0087 struct iwl_rx_packet *pkt, void *data),
0088 void *fn_data)
0089 {
0090 if (WARN_ON(n_cmds > MAX_NOTIF_CMDS))
0091 n_cmds = MAX_NOTIF_CMDS;
0092
0093 wait_entry->fn = fn;
0094 wait_entry->fn_data = fn_data;
0095 wait_entry->n_cmds = n_cmds;
0096 memcpy(wait_entry->cmds, cmds, n_cmds * sizeof(u16));
0097 wait_entry->triggered = false;
0098 wait_entry->aborted = false;
0099
0100 spin_lock_bh(¬if_wait->notif_wait_lock);
0101 list_add(&wait_entry->list, ¬if_wait->notif_waits);
0102 spin_unlock_bh(¬if_wait->notif_wait_lock);
0103 }
0104 IWL_EXPORT_SYMBOL(iwl_init_notification_wait);
0105
0106 void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,
0107 struct iwl_notification_wait *wait_entry)
0108 {
0109 spin_lock_bh(¬if_wait->notif_wait_lock);
0110 list_del(&wait_entry->list);
0111 spin_unlock_bh(¬if_wait->notif_wait_lock);
0112 }
0113 IWL_EXPORT_SYMBOL(iwl_remove_notification);
0114
0115 int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,
0116 struct iwl_notification_wait *wait_entry,
0117 unsigned long timeout)
0118 {
0119 int ret;
0120
0121 ret = wait_event_timeout(notif_wait->notif_waitq,
0122 wait_entry->triggered || wait_entry->aborted,
0123 timeout);
0124
0125 iwl_remove_notification(notif_wait, wait_entry);
0126
0127 if (wait_entry->aborted)
0128 return -EIO;
0129
0130
0131 if (ret <= 0)
0132 return -ETIMEDOUT;
0133 return 0;
0134 }
0135 IWL_EXPORT_SYMBOL(iwl_wait_notification);