1 /*
2 * Copyright (c) 2021 Huawei Device Co., Ltd.
3 *
4 * HDF is dual licensed: you can use it either under the terms of
5 * the GPL, or the BSD license, at your option.
6 * See the LICENSE file in the root of this repository for complete details.
7 */
8
9 #include "platform_event.h"
10 #include "hdf_dlist.h"
11 #include "osal_mem.h"
12 #include "osal_sem.h"
13 #include "platform_errno.h"
14 #include "platform_log.h"
15
16 #ifdef __cplusplus
17 #if __cplusplus
18 extern "C" {
19 #endif
20 #endif /* __cplusplus */
21
22 struct PlatformEventWaiter {
23 struct DListHead node;
24 struct OsalSem sem;
25 uint32_t mask;
26 uint32_t mode;
27 void *data;
28 int32_t (*cb)(struct PlatformEventWaiter *waiter, int32_t events);
29 };
30
PlatformEventInit(struct PlatformEvent * pe)31 int32_t PlatformEventInit(struct PlatformEvent *pe)
32 {
33 if (pe == NULL) {
34 return HDF_ERR_INVALID_OBJECT;
35 }
36 pe->eventsWord = 0;
37 pe->waiterCnt = 0;
38 DListHeadInit(&pe->waiters);
39 (void)OsalSpinInit(&pe->spin);
40 (void)OsalSemInit(&pe->sem, 0);
41 return HDF_SUCCESS;
42 }
43
PlatformEventLock(struct PlatformEvent * pe)44 static void PlatformEventLock(struct PlatformEvent *pe)
45 {
46 (void)OsalSpinLockIrqSave(&pe->spin, &pe->irqSave);
47 }
48
PlatformEventUnlock(struct PlatformEvent * pe)49 static void PlatformEventUnlock(struct PlatformEvent *pe)
50 {
51 (void)OsalSpinUnlockIrqRestore(&pe->spin, &pe->irqSave);
52 }
53
PlatformEventClearWaiters(struct PlatformEvent * pe)54 static void PlatformEventClearWaiters(struct PlatformEvent *pe)
55 {
56 struct PlatformEventWaiter *waiter = NULL;
57 struct PlatformEventWaiter *tmp = NULL;
58
59 PlatformEventLock(pe);
60 DLIST_FOR_EACH_ENTRY_SAFE(waiter, tmp, &pe->waiters, struct PlatformEventWaiter, node) {
61 DListRemove(&waiter->node);
62 if ((waiter->mode & PLAT_EVENT_MODE_ASYNC) != 0) {
63 OsalMemFree(waiter);
64 }
65 }
66 PlatformEventUnlock(pe);
67 }
68
PlatformEventUninit(struct PlatformEvent * pe)69 int32_t PlatformEventUninit(struct PlatformEvent *pe)
70 {
71 if (pe == NULL) {
72 return HDF_ERR_INVALID_OBJECT;
73 }
74 PlatformEventClearWaiters(pe);
75 (void)OsalSemDestroy(&pe->sem);
76 (void)OsalSpinDestroy(&pe->spin);
77 return HDF_SUCCESS;
78 }
79
PlatformEventPost(struct PlatformEvent * pe,uint32_t events)80 int32_t PlatformEventPost(struct PlatformEvent *pe, uint32_t events)
81 {
82 int32_t ret;
83 uint32_t masked;
84 struct PlatformEventWaiter *waiter = NULL;
85 struct PlatformEventWaiter *pos = NULL;
86 struct PlatformEventWaiter *tmp = NULL;
87
88 if (pe == NULL) {
89 return HDF_ERR_INVALID_OBJECT;
90 }
91 if (events == 0) {
92 return HDF_ERR_INVALID_PARAM;
93 }
94
95 PlatformEventLock(pe);
96 pe->eventsWord |= events;
97 DLIST_FOR_EACH_ENTRY_SAFE(pos, tmp, &pe->waiters, struct PlatformEventWaiter, node) {
98 if (((pos->mode & PLAT_EVENT_MODE_AND) == 0) &&
99 ((pe->eventsWord & pos->mask) != 0)) {
100 waiter = pos;
101 break;
102 }
103 if (((pos->mode & PLAT_EVENT_MODE_AND) != 0) &&
104 ((pe->eventsWord & pos->mask) == pos->mask)) {
105 waiter = pos;
106 break;
107 }
108 }
109 if (waiter != NULL) {
110 masked = pe->eventsWord & waiter->mask;
111 if ((waiter->mode & PLAT_EVENT_MODE_ASYNC) != 0) {
112 pe->eventsWord &= ~masked;
113 } else {
114 DListRemove(&waiter->node);
115 }
116 }
117 PlatformEventUnlock(pe);
118
119 if (waiter == NULL) {
120 return HDF_SUCCESS;
121 }
122
123 if ((waiter->mode & PLAT_EVENT_MODE_ASYNC) == 0) {
124 ret = OsalSemPost(&waiter->sem);
125 } else if (waiter->cb != NULL) {
126 ret = waiter->cb(waiter, masked);
127 } else {
128 ret = HDF_ERR_INVALID_PARAM;
129 }
130
131 return ret;
132 }
133
PlatformEventRead(struct PlatformEvent * pe,uint32_t * events,uint32_t mask,int32_t mode)134 static int32_t PlatformEventRead(struct PlatformEvent *pe, uint32_t *events, uint32_t mask, int32_t mode)
135 {
136 uint32_t masked = 0;
137
138 if (events == NULL || mask == 0) {
139 return HDF_ERR_INVALID_PARAM;
140 }
141 PlatformEventLock(pe);
142 if (((uint32_t)mode & (uint32_t)PLAT_EVENT_MODE_AND) == 0) {
143 if ((pe->eventsWord & mask) != 0) {
144 masked = pe->eventsWord & mask;
145 }
146 } else {
147 if ((pe->eventsWord & mask) == mask) {
148 masked = pe->eventsWord & mask;
149 }
150 }
151 pe->eventsWord &= ~masked; // clear the bits default
152 PlatformEventUnlock(pe);
153
154 *events = masked;
155 return HDF_SUCCESS;
156 }
157
PlatformEventReadSlowlly(struct PlatformEvent * pe,uint32_t * events,uint32_t mask,int32_t mode,uint32_t tms)158 static int32_t PlatformEventReadSlowlly(struct PlatformEvent *pe,
159 uint32_t *events, uint32_t mask, int32_t mode, uint32_t tms)
160 {
161 int32_t ret;
162 struct PlatformEventWaiter waiter;
163
164 waiter.mask = mask;
165 waiter.mode = (uint32_t)mode & (uint32_t)(~PLAT_EVENT_MODE_ASYNC);
166 (void)OsalSemInit(&waiter.sem, 0);
167 DListHeadInit(&waiter.node);
168
169 PlatformEventLock(pe);
170 DListInsertTail(&waiter.node, &pe->waiters);
171 PlatformEventUnlock(pe);
172
173 ret = OsalSemWait(&waiter.sem, tms);
174 if (ret == HDF_SUCCESS) {
175 (void)OsalSemDestroy(&waiter.sem);
176 return PlatformEventRead(pe, events, mask, mode);
177 }
178
179 PlatformEventLock(pe);
180 // the waiter may be still in the list, we need to check...
181 if (waiter.node.next != NULL && !DListIsEmpty(&waiter.node)) {
182 DListRemove(&waiter.node);
183 }
184 PlatformEventUnlock(pe);
185
186 (void)OsalSemDestroy(&waiter.sem);
187 return ret;
188 }
189
PlatformEventWait(struct PlatformEvent * pe,uint32_t mask,int32_t mode,uint32_t tms,uint32_t * events)190 int32_t PlatformEventWait(struct PlatformEvent *pe, uint32_t mask, int32_t mode, uint32_t tms, uint32_t *events)
191 {
192 int32_t ret;
193 uint32_t eventsRead;
194
195 if (pe == NULL) {
196 return HDF_ERR_INVALID_OBJECT;
197 }
198 if (events == NULL || mask == 0) {
199 return HDF_ERR_INVALID_PARAM;
200 }
201
202 ret = PlatformEventRead(pe, &eventsRead, mask, mode);
203 if (ret != HDF_SUCCESS) {
204 return ret;
205 }
206
207 if (eventsRead != 0) {
208 *events = eventsRead;
209 return HDF_SUCCESS;
210 }
211
212 if (tms == 0) {
213 return HDF_PLT_ERR_NO_DATA;
214 }
215
216 return PlatformEventReadSlowlly(pe, events, mask, mode, tms);
217 }
218
PlatformEventAsyncCallback(struct PlatformEventWaiter * waiter,int32_t events)219 static int32_t PlatformEventAsyncCallback(struct PlatformEventWaiter *waiter, int32_t events)
220 {
221 struct PlatformEventListener *listener = (struct PlatformEventListener *)waiter->data;
222
223 if (listener == NULL) {
224 return HDF_ERR_INVALID_PARAM;
225 }
226
227 // gona do it in thread context later ...
228 return listener->cb(listener, (uint32_t)events & listener->mask);
229 }
230
PlatformEventListen(struct PlatformEvent * pe,const struct PlatformEventListener * listener)231 int32_t PlatformEventListen(struct PlatformEvent *pe, const struct PlatformEventListener *listener)
232 {
233 struct PlatformEventWaiter *waiter = NULL;
234
235 if (pe == NULL || listener == NULL) {
236 return HDF_ERR_INVALID_OBJECT;
237 }
238 if (listener->mask == 0 || listener->cb == NULL) {
239 return HDF_ERR_INVALID_PARAM;
240 }
241
242 waiter = (struct PlatformEventWaiter *)OsalMemCalloc(sizeof(*waiter));
243 if (waiter == NULL) {
244 return HDF_ERR_MALLOC_FAIL;
245 }
246 waiter->mask = listener->mask;
247 waiter->data = (void *)listener;
248 waiter->mode = PLAT_EVENT_MODE_ASYNC;
249 waiter->cb = PlatformEventAsyncCallback;
250
251 PlatformEventLock(pe);
252 DListHeadInit(&waiter->node);
253 DListInsertTail(&waiter->node, &pe->waiters);
254 PlatformEventUnlock(pe);
255
256 return HDF_SUCCESS;
257 }
258
PlatformEventUnlisten(struct PlatformEvent * pe,const struct PlatformEventListener * listener)259 void PlatformEventUnlisten(struct PlatformEvent *pe, const struct PlatformEventListener *listener)
260 {
261 struct PlatformEventWaiter *waiter = NULL;
262 struct PlatformEventWaiter *tmp = NULL;
263
264 if (pe == NULL || listener == NULL) {
265 return;
266 }
267
268 PlatformEventLock(pe);
269 DLIST_FOR_EACH_ENTRY_SAFE(waiter, tmp, &pe->waiters, struct PlatformEventWaiter, node) {
270 if ((waiter->mode & PLAT_EVENT_MODE_ASYNC) == 0) {
271 continue;
272 }
273 if (waiter->data == (void *)listener) {
274 DListRemove(&waiter->node);
275 OsalMemFree(waiter);
276 break;
277 }
278 }
279 PlatformEventUnlock(pe);
280 }
281
282 #ifdef __cplusplus
283 #if __cplusplus
284 }
285 #endif
286 #endif /* __cplusplus */
287