1 /*
2  * Copyright (c) 2020 Raspberry Pi (Trading) Ltd.
3  *
4  * SPDX-License-Identifier: BSD-3-Clause
5  */
6 
7 #ifndef _HARDWARE_SYNC_H
8 #define _HARDWARE_SYNC_H
9 
10 #include "pico.h"
11 
12 #ifndef __cplusplus
13 
14 #if (__STDC_VERSION__ >= 201112L)
15 #include <stdatomic.h>
16 #else
17 enum {
18     memory_order_acquire, memory_order_release
19 };
atomic_thread_fence(uint x)20 static inline void atomic_thread_fence(uint x) {}
21 #endif
22 
23 #else
24 
25 #include <atomic>
26 
27 #endif
28 
29 // PICO_CONFIG: PICO_SPINLOCK_ID_ATOMIC, Spinlock ID for atomics, min=0, max=31, default=8, group=hardware_sync
30 #ifndef PICO_SPINLOCK_ID_ATOMIC
31 #define PICO_SPINLOCK_ID_ATOMIC 8
32 #endif
33 
34 // PICO_CONFIG: PICO_SPINLOCK_ID_IRQ, Spinlock ID for IRQ protection, min=0, max=31, default=9, group=hardware_sync
35 #ifndef PICO_SPINLOCK_ID_IRQ
36 #define PICO_SPINLOCK_ID_IRQ 9
37 #endif
38 
39 // PICO_CONFIG: PICO_SPINLOCK_ID_TIMER, Spinlock ID for Timer protection, min=0, max=31, default=10, group=hardware_sync
40 #ifndef PICO_SPINLOCK_ID_TIMER
41 #define PICO_SPINLOCK_ID_TIMER 10
42 #endif
43 
44 // PICO_CONFIG: PICO_SPINLOCK_ID_HARDWARE_CLAIM, Spinlock ID for Hardware claim protection, min=0, max=31, default=11, group=hardware_sync
45 #ifndef PICO_SPINLOCK_ID_HARDWARE_CLAIM
46 #define PICO_SPINLOCK_ID_HARDWARE_CLAIM 11
47 #endif
48 
49 // PICO_CONFIG: PICO_SPINLOCK_ID_RAND, Spinlock ID for Random Number Generator, min=0, max=31, default=12, group=hardware_sync
50 #ifndef PICO_SPINLOCK_ID_RAND
51 #define PICO_SPINLOCK_ID_RAND 12
52 #endif
53 
54 // PICO_CONFIG: PICO_SPINLOCK_ID_OS1, First Spinlock ID reserved for use by low level OS style software, min=0, max=31, default=14, group=hardware_sync
55 #ifndef PICO_SPINLOCK_ID_OS1
56 #define PICO_SPINLOCK_ID_OS1 14
57 #endif
58 
59 // PICO_CONFIG: PICO_SPINLOCK_ID_OS2, Second Spinlock ID reserved for use by low level OS style software, min=0, max=31, default=15, group=hardware_sync
60 #ifndef PICO_SPINLOCK_ID_OS2
61 #define PICO_SPINLOCK_ID_OS2 15
62 #endif
63 
64 // PICO_CONFIG: PICO_SPINLOCK_ID_STRIPED_FIRST, Lowest Spinlock ID in the 'striped' range, min=0, max=31, default=16, group=hardware_sync
65 #ifndef PICO_SPINLOCK_ID_STRIPED_FIRST
66 #define PICO_SPINLOCK_ID_STRIPED_FIRST 16
67 #endif
68 
69 // PICO_CONFIG: PICO_SPINLOCK_ID_STRIPED_LAST, Highest Spinlock ID in the 'striped' range, min=0, max=31, default=23, group=hardware_sync
70 #ifndef PICO_SPINLOCK_ID_STRIPED_LAST
71 #define PICO_SPINLOCK_ID_STRIPED_LAST 23
72 #endif
73 
74 // PICO_CONFIG: PICO_SPINLOCK_ID_CLAIM_FREE_FIRST, Lowest Spinlock ID in the 'claim free' range, min=0, max=31, default=24, group=hardware_sync
75 #ifndef PICO_SPINLOCK_ID_CLAIM_FREE_FIRST
76 #define PICO_SPINLOCK_ID_CLAIM_FREE_FIRST 24
77 #endif
78 
79 #ifdef PICO_SPINLOCK_ID_CLAIM_FREE_END
80 #warning PICO_SPINLOCK_ID_CLAIM_FREE_END has been renamed to PICO_SPINLOCK_ID_CLAIM_FREE_LAST
81 #endif
82 
83 // PICO_CONFIG: PICO_SPINLOCK_ID_CLAIM_FREE_LAST, Highest Spinlock ID in the 'claim free' range, min=0, max=31, default=31, group=hardware_sync
84 #ifndef PICO_SPINLOCK_ID_CLAIM_FREE_LAST
85 #define PICO_SPINLOCK_ID_CLAIM_FREE_LAST 31
86 #endif
87 
88 typedef struct _spin_lock_t spin_lock_t;
89 
__mem_fence_acquire()90 inline static void __mem_fence_acquire() {
91 #ifndef __cplusplus
92     atomic_thread_fence(memory_order_acquire);
93 #else
94     std::atomic_thread_fence(std::memory_order_acquire);
95 #endif
96 }
97 
__mem_fence_release()98 inline static void __mem_fence_release() {
99 #ifndef __cplusplus
100     atomic_thread_fence(memory_order_release);
101 #else
102     std::atomic_thread_fence(std::memory_order_release);
103 #endif
104 }
105 
106 #ifdef __cplusplus
107 extern "C" {
108 #endif
109 
110 void __sev();
111 
112 void __wev();
113 
114 void __wfi();
115 
116 void __wfe();
117 
118 uint32_t save_and_disable_interrupts();
119 
120 void restore_interrupts(uint32_t status);
121 
122 void restore_interrupts_from_disabled(uint32_t status);
123 
124 uint spin_lock_get_num(spin_lock_t *lock);
125 
126 spin_lock_t *spin_lock_instance(uint lock_num);
127 
128 void spin_lock_unsafe_blocking(spin_lock_t *lock);
129 
130 void spin_unlock_unsafe(spin_lock_t *lock);
131 
132 uint32_t spin_lock_blocking(spin_lock_t *lock);
133 
134 bool is_spin_locked(const spin_lock_t *lock);
135 
136 void spin_unlock(spin_lock_t *lock, uint32_t saved_irq);
137 
138 spin_lock_t *spin_lock_init(uint lock_num);
139 
140 void clear_spin_locks(void);
141 #define spin_locks_reset() clear_spin_locks()
142 
143 uint next_striped_spin_lock_num();
144 
145 void spin_lock_claim(uint lock_num);
146 void spin_lock_claim_mask(uint32_t lock_num_mask);
147 void spin_lock_unclaim(uint lock_num);
148 int spin_lock_claim_unused(bool required);
149 uint spin_lock_num(spin_lock_t *lock);
150 
151 #ifdef __cplusplus
152 }
153 #endif
154 #endif
155