1 // © 2021 Qualcomm Innovation Center, Inc. All rights reserved.
2 //
3 // SPDX-License-Identifier: BSD-3-Clause
4 
5 // Wait for or raise events.
6 //
7 // These macros may apply architecture-specific optimisations to improve the
8 // efficiency of inter-CPU signalling by polling shared variables.
9 //
10 // These are the default definitions, which provide adequate memory barriers
11 // but otherwise just busy-wait. This header should only be included by the
12 // architecture-specific asm/event.h, which can optionally define the
13 // asm_event_wait() macro to an operation that may sleep, and also define the
14 // other operations if necessary.
15 
16 // Load a polled variable before a possible asm_event_wait().
17 //
18 // This load must be an acquire operation on the specified variable.
19 //
20 // To be safe on platforms that sleep in asm_event_wait(), the return value of
21 // this macro _must_ be used in an expression that determines whether to
22 // call asm_event_wait().
23 #if !defined(asm_event_load_before_wait)
24 #define asm_event_load_before_wait(p)                                          \
25 	atomic_load_explicit(p, memory_order_acquire)
26 #endif
27 
28 // As above, but for a named bitfield type.
29 //
30 // This is needed to hide pointer casts that would otherwise be unsafe on
31 // platforms where asm_event_load_before_wait() needs type-specific inline asm,
32 // such as ARMv8.
33 #if !defined(asm_event_load_bf_before_wait)
34 #define asm_event_load_bf_before_wait(name, p) asm_event_load_before_wait(p)
35 #endif
36 
37 // Poll after checking the result of asm_event_load_before_wait().
38 //
39 // Polling may place the calling CPU in a low-power halt state until the
40 // value read by asm_event_load_before_wait() is updated by either a remote CPU,
41 // or a local interrupt handler that interrupts the poll. The polled variable
42 // must be updated by either calling asm_event_store_and_wake(), or with some
43 // other store operation followed by a call to asm_event_wake_updated().
44 //
45 // Updates performed by remote CPUs in any other way, or performed by the local
46 // CPU other than in an interrupt handler that preempts the poll, are not
47 // guaranteed to wake a sleeping poll.
48 //
49 // Polling must be safe from races; that is, asm_event_wait() must return if
50 // an update inter-thread happens after asm_event_load_before_wait(), regardless
51 // of whether the update inter-thread happens after asm_event_wait() is called.
52 //
53 // Polling is not required to sleep until the polled value is updated;
54 // it may wake early or not sleep at all. If the CPU does not support this
55 // operation and will never sleep, ASM_EVENT_WAIT_IS_NOOP is defined to be
56 // nonzero.
57 #if !defined(asm_event_wait)
58 #define ASM_EVENT_WAIT_IS_NOOP 1
59 #define asm_event_wait(p)      ((void)0)
60 #else
61 #define ASM_EVENT_WAIT_IS_NOOP 0
62 #endif
63 
64 // Store an event variable and wake CPUs waiting on it.
65 //
66 // This store must be a release operation on the specified variable.
67 #if !defined(asm_event_store_and_wake)
68 #define asm_event_store_and_wake(p, v)                                         \
69 	atomic_store_explicit((p), (v), memory_order_release)
70 #endif
71 
72 // Wake CPUs waiting on one or more variables that have been updated with direct
73 // atomic_*() calls rather than by calling asm_event_store_and_wake().
74 //
75 // Any direct updates must either be release operations, or else followed by
76 // a release fence, prior to executing this operation.
77 //
78 // This may be more expensive than asm_event_store_and_wake(), especially for a
79 // single store.
80 #if !defined(asm_event_wake_updated)
81 #define asm_event_wake_updated() (void)0
82 #endif
83