Back to home page

OSCL-LXR

 
 

    


0001 // SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause
0002 /*
0003  * Copyright (C) 2005-2014, 2021 Intel Corporation
0004  * Copyright (C) 2015-2017 Intel Deutschland GmbH
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(&notif_wait->notif_wait_lock);
0016     INIT_LIST_HEAD(&notif_wait->notif_waits);
0017     init_waitqueue_head(&notif_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(&notif_wait->notif_waits)) {
0027         struct iwl_notification_wait *w;
0028 
0029         spin_lock_bh(&notif_wait->notif_wait_lock);
0030         list_for_each_entry(w, &notif_wait->notif_waits, list) {
0031             int i;
0032             bool found = false;
0033 
0034             /*
0035              * If it already finished (triggered) or has been
0036              * aborted then don't evaluate it again to avoid races,
0037              * Otherwise the function could be called again even
0038              * though it returned true before
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(&notif_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(&notif_wait->notif_wait_lock);
0074     list_for_each_entry(wait_entry, &notif_wait->notif_waits, list)
0075         wait_entry->aborted = true;
0076     spin_unlock_bh(&notif_wait->notif_wait_lock);
0077 
0078     wake_up_all(&notif_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(&notif_wait->notif_wait_lock);
0101     list_add(&wait_entry->list, &notif_wait->notif_waits);
0102     spin_unlock_bh(&notif_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(&notif_wait->notif_wait_lock);
0110     list_del(&wait_entry->list);
0111     spin_unlock_bh(&notif_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     /* return value is always >= 0 */
0131     if (ret <= 0)
0132         return -ETIMEDOUT;
0133     return 0;
0134 }
0135 IWL_EXPORT_SYMBOL(iwl_wait_notification);