162306a36Sopenharmony_ci/* SPDX-License-Identifier: GPL-2.0 OR BSD-3-Clause */
262306a36Sopenharmony_ci/*
362306a36Sopenharmony_ci * Copyright (C) 2005-2014 Intel Corporation
462306a36Sopenharmony_ci * Copyright (C) 2015-2017 Intel Deutschland GmbH
562306a36Sopenharmony_ci */
662306a36Sopenharmony_ci#ifndef __iwl_notif_wait_h__
762306a36Sopenharmony_ci#define __iwl_notif_wait_h__
862306a36Sopenharmony_ci
962306a36Sopenharmony_ci#include <linux/wait.h>
1062306a36Sopenharmony_ci
1162306a36Sopenharmony_ci#include "iwl-trans.h"
1262306a36Sopenharmony_ci
1362306a36Sopenharmony_cistruct iwl_notif_wait_data {
1462306a36Sopenharmony_ci	struct list_head notif_waits;
1562306a36Sopenharmony_ci	spinlock_t notif_wait_lock;
1662306a36Sopenharmony_ci	wait_queue_head_t notif_waitq;
1762306a36Sopenharmony_ci};
1862306a36Sopenharmony_ci
1962306a36Sopenharmony_ci#define MAX_NOTIF_CMDS	5
2062306a36Sopenharmony_ci
2162306a36Sopenharmony_ci/**
2262306a36Sopenharmony_ci * struct iwl_notification_wait - notification wait entry
2362306a36Sopenharmony_ci * @list: list head for global list
2462306a36Sopenharmony_ci * @fn: Function called with the notification. If the function
2562306a36Sopenharmony_ci *	returns true, the wait is over, if it returns false then
2662306a36Sopenharmony_ci *	the waiter stays blocked. If no function is given, any
2762306a36Sopenharmony_ci *	of the listed commands will unblock the waiter.
2862306a36Sopenharmony_ci * @cmds: command IDs
2962306a36Sopenharmony_ci * @n_cmds: number of command IDs
3062306a36Sopenharmony_ci * @triggered: waiter should be woken up
3162306a36Sopenharmony_ci * @aborted: wait was aborted
3262306a36Sopenharmony_ci *
3362306a36Sopenharmony_ci * This structure is not used directly, to wait for a
3462306a36Sopenharmony_ci * notification declare it on the stack, and call
3562306a36Sopenharmony_ci * iwl_init_notification_wait() with appropriate
3662306a36Sopenharmony_ci * parameters. Then do whatever will cause the ucode
3762306a36Sopenharmony_ci * to notify the driver, and to wait for that then
3862306a36Sopenharmony_ci * call iwl_wait_notification().
3962306a36Sopenharmony_ci *
4062306a36Sopenharmony_ci * Each notification is one-shot. If at some point we
4162306a36Sopenharmony_ci * need to support multi-shot notifications (which
4262306a36Sopenharmony_ci * can't be allocated on the stack) we need to modify
4362306a36Sopenharmony_ci * the code for them.
4462306a36Sopenharmony_ci */
4562306a36Sopenharmony_cistruct iwl_notification_wait {
4662306a36Sopenharmony_ci	struct list_head list;
4762306a36Sopenharmony_ci
4862306a36Sopenharmony_ci	bool (*fn)(struct iwl_notif_wait_data *notif_data,
4962306a36Sopenharmony_ci		   struct iwl_rx_packet *pkt, void *data);
5062306a36Sopenharmony_ci	void *fn_data;
5162306a36Sopenharmony_ci
5262306a36Sopenharmony_ci	u16 cmds[MAX_NOTIF_CMDS];
5362306a36Sopenharmony_ci	u8 n_cmds;
5462306a36Sopenharmony_ci	bool triggered, aborted;
5562306a36Sopenharmony_ci};
5662306a36Sopenharmony_ci
5762306a36Sopenharmony_ci
5862306a36Sopenharmony_ci/* caller functions */
5962306a36Sopenharmony_civoid iwl_notification_wait_init(struct iwl_notif_wait_data *notif_data);
6062306a36Sopenharmony_cibool iwl_notification_wait(struct iwl_notif_wait_data *notif_data,
6162306a36Sopenharmony_ci			   struct iwl_rx_packet *pkt);
6262306a36Sopenharmony_civoid iwl_abort_notification_waits(struct iwl_notif_wait_data *notif_data);
6362306a36Sopenharmony_ci
6462306a36Sopenharmony_cistatic inline void
6562306a36Sopenharmony_ciiwl_notification_notify(struct iwl_notif_wait_data *notif_data)
6662306a36Sopenharmony_ci{
6762306a36Sopenharmony_ci	wake_up_all(&notif_data->notif_waitq);
6862306a36Sopenharmony_ci}
6962306a36Sopenharmony_ci
7062306a36Sopenharmony_cistatic inline void
7162306a36Sopenharmony_ciiwl_notification_wait_notify(struct iwl_notif_wait_data *notif_data,
7262306a36Sopenharmony_ci			     struct iwl_rx_packet *pkt)
7362306a36Sopenharmony_ci{
7462306a36Sopenharmony_ci	if (iwl_notification_wait(notif_data, pkt))
7562306a36Sopenharmony_ci		iwl_notification_notify(notif_data);
7662306a36Sopenharmony_ci}
7762306a36Sopenharmony_ci
7862306a36Sopenharmony_ci/* user functions */
7962306a36Sopenharmony_civoid __acquires(wait_entry)
8062306a36Sopenharmony_ciiwl_init_notification_wait(struct iwl_notif_wait_data *notif_data,
8162306a36Sopenharmony_ci			   struct iwl_notification_wait *wait_entry,
8262306a36Sopenharmony_ci			   const u16 *cmds, int n_cmds,
8362306a36Sopenharmony_ci			   bool (*fn)(struct iwl_notif_wait_data *notif_data,
8462306a36Sopenharmony_ci				      struct iwl_rx_packet *pkt, void *data),
8562306a36Sopenharmony_ci			   void *fn_data);
8662306a36Sopenharmony_ci
8762306a36Sopenharmony_ciint __must_check __releases(wait_entry)
8862306a36Sopenharmony_ciiwl_wait_notification(struct iwl_notif_wait_data *notif_data,
8962306a36Sopenharmony_ci		      struct iwl_notification_wait *wait_entry,
9062306a36Sopenharmony_ci		      unsigned long timeout);
9162306a36Sopenharmony_ci
9262306a36Sopenharmony_civoid __releases(wait_entry)
9362306a36Sopenharmony_ciiwl_remove_notification(struct iwl_notif_wait_data *notif_data,
9462306a36Sopenharmony_ci			struct iwl_notification_wait *wait_entry);
9562306a36Sopenharmony_ci
9662306a36Sopenharmony_ci#endif /* __iwl_notif_wait_h__ */
97