136 lines · c
1// SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause2/*3 * Copyright (C) 2005-2014, 2021 Intel Corporation4 * Copyright (C) 2015-2017 Intel Deutschland GmbH5 */6#include <linux/sched.h>7#include <linux/export.h>8 9#include "iwl-drv.h"10#include "notif-wait.h"11 12 13void iwl_notification_wait_init(struct iwl_notif_wait_data *notif_wait)14{15 spin_lock_init(¬if_wait->notif_wait_lock);16 INIT_LIST_HEAD(¬if_wait->notif_waits);17 init_waitqueue_head(¬if_wait->notif_waitq);18}19IWL_EXPORT_SYMBOL(iwl_notification_wait_init);20 21bool iwl_notification_wait(struct iwl_notif_wait_data *notif_wait,22 struct iwl_rx_packet *pkt)23{24 bool triggered = false;25 26 if (!list_empty(¬if_wait->notif_waits)) {27 struct iwl_notification_wait *w;28 29 spin_lock_bh(¬if_wait->notif_wait_lock);30 list_for_each_entry(w, ¬if_wait->notif_waits, list) {31 int i;32 bool found = false;33 34 /*35 * If it already finished (triggered) or has been36 * aborted then don't evaluate it again to avoid races,37 * Otherwise the function could be called again even38 * though it returned true before39 */40 if (w->triggered || w->aborted)41 continue;42 43 for (i = 0; i < w->n_cmds; i++) {44 u16 rec_id = WIDE_ID(pkt->hdr.group_id,45 pkt->hdr.cmd);46 47 if (w->cmds[i] == rec_id ||48 (!iwl_cmd_groupid(w->cmds[i]) &&49 DEF_ID(w->cmds[i]) == rec_id)) {50 found = true;51 break;52 }53 }54 if (!found)55 continue;56 57 if (!w->fn || w->fn(notif_wait, pkt, w->fn_data)) {58 w->triggered = true;59 triggered = true;60 }61 }62 spin_unlock_bh(¬if_wait->notif_wait_lock);63 }64 65 return triggered;66}67IWL_EXPORT_SYMBOL(iwl_notification_wait);68 69void iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_wait)70{71 struct iwl_notification_wait *wait_entry;72 73 spin_lock_bh(¬if_wait->notif_wait_lock);74 list_for_each_entry(wait_entry, ¬if_wait->notif_waits, list)75 wait_entry->aborted = true;76 spin_unlock_bh(¬if_wait->notif_wait_lock);77 78 wake_up_all(¬if_wait->notif_waitq);79}80IWL_EXPORT_SYMBOL(iwl_abort_notification_waits);81 82void83iwl_init_notification_wait(struct iwl_notif_wait_data *notif_wait,84 struct iwl_notification_wait *wait_entry,85 const u16 *cmds, int n_cmds,86 bool (*fn)(struct iwl_notif_wait_data *notif_wait,87 struct iwl_rx_packet *pkt, void *data),88 void *fn_data)89{90 if (WARN_ON(n_cmds > MAX_NOTIF_CMDS))91 n_cmds = MAX_NOTIF_CMDS;92 93 wait_entry->fn = fn;94 wait_entry->fn_data = fn_data;95 wait_entry->n_cmds = n_cmds;96 memcpy(wait_entry->cmds, cmds, n_cmds * sizeof(u16));97 wait_entry->triggered = false;98 wait_entry->aborted = false;99 100 spin_lock_bh(¬if_wait->notif_wait_lock);101 list_add(&wait_entry->list, ¬if_wait->notif_waits);102 spin_unlock_bh(¬if_wait->notif_wait_lock);103}104IWL_EXPORT_SYMBOL(iwl_init_notification_wait);105 106void iwl_remove_notification(struct iwl_notif_wait_data *notif_wait,107 struct iwl_notification_wait *wait_entry)108{109 spin_lock_bh(¬if_wait->notif_wait_lock);110 list_del(&wait_entry->list);111 spin_unlock_bh(¬if_wait->notif_wait_lock);112}113IWL_EXPORT_SYMBOL(iwl_remove_notification);114 115int iwl_wait_notification(struct iwl_notif_wait_data *notif_wait,116 struct iwl_notification_wait *wait_entry,117 unsigned long timeout)118{119 int ret;120 121 ret = wait_event_timeout(notif_wait->notif_waitq,122 wait_entry->triggered || wait_entry->aborted,123 timeout);124 125 iwl_remove_notification(notif_wait, wait_entry);126 127 if (wait_entry->aborted)128 return -EIO;129 130 /* return value is always >= 0 */131 if (ret <= 0)132 return -ETIMEDOUT;133 return 0;134}135IWL_EXPORT_SYMBOL(iwl_wait_notification);136