1 /*
2 * Copyright (C) 2016 The Android Open Source Project
3 *
4 * Licensed under the Apache License, Version 2.0 (the "License");
5 * you may not use this file except in compliance with the License.
6 * You may obtain a copy of the License at
7 *
8 * http://www.apache.org/licenses/LICENSE-2.0
9 *
10 * Unless required by applicable law or agreed to in writing, software
11 * distributed under the License is distributed on an "AS IS" BASIS,
12 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
13 * See the License for the specific language governing permissions and
14 * limitations under the License.
15 */
16
17 #include <cpu/atomicBitset.h>
18 #include <plat/rtc.h>
19 #include <atomicBitset.h>
20 #include <platform.h>
21 #include <atomic.h>
22 #include <stdlib.h>
23 #include <stdio.h>
24 #include <timer.h>
25 #include <seos.h>
26 #include <cpu.h>
27 #include <slab.h>
28 #include <util.h>
29
30 #include "seos_priv.h"
31
32 #define MAX_INTERNAL_EVENTS 32 //also used for external app timer() calls
33
34 #define MAX_TIMER_ID 0xFF
35
36 #define INFO_PRINT(fmt, ...) do { \
37 osLog(LOG_INFO, "%s " fmt, "[timer]", ##__VA_ARGS__); \
38 } while (0);
39
40 #define ERROR_PRINT(fmt, ...) INFO_PRINT("%s" fmt, "ERROR: ", ##__VA_ARGS__)
41
42 struct Timer {
43 uint64_t expires; /* time of next expiration */
44 uint64_t period; /* 0 for oneshot */
45 uint8_t id; /* 0 for disabled */
46 uint8_t useRtc; /* 1 for rtc, 0 for tim */
47 uint16_t tid; /* we need TID always, for system management */
48 uint32_t jitterPpm;
49 uint32_t driftPpm;
50 TaggedPtr callInfo;
51 void *callData;
52 };
53
54
55 ATOMIC_BITSET_DECL(mTimersValid, MAX_TIMERS, static);
56 static struct SlabAllocator *mInternalEvents;
57 static struct Timer mTimers[MAX_TIMERS];
58 static volatile uint32_t mNextTimerId = 0;
59
timGetTime(void)60 uint64_t timGetTime(void)
61 {
62 return platGetTicks();
63 }
64
timDelay(uint32_t length)65 void timDelay(uint32_t length)
66 {
67 uint64_t curTime = timGetTime();
68
69 while (curTime + length > timGetTime())
70 ;
71 }
72
timFindTimerById(uint32_t timId)73 static struct Timer *timFindTimerById(uint32_t timId) /* no locks taken. be careful what you do with this */
74 {
75 uint32_t i;
76
77 for (i = 0; i < MAX_TIMERS; i++)
78 if (mTimers[i].id == timId)
79 return mTimers + i;
80
81 return NULL;
82 }
83
timerCallFuncFreeF(void * event)84 static void timerCallFuncFreeF(void* event)
85 {
86 slabAllocatorFree(mInternalEvents, event);
87 }
88
timCallFunc(struct Timer * tim)89 static void timCallFunc(struct Timer *tim)
90 {
91 struct TimerEvent *evt;
92 TaggedPtr callInfo = tim->callInfo;
93
94 if (taggedPtrIsPtr(callInfo)) {
95 osSetCurrentTid(tim->tid);
96 ((TimTimerCbkF)taggedPtrToPtr(callInfo))(tim->id, tim->callData);
97 } else {
98 osSetCurrentTid(OS_SYSTEM_TID);
99 if ((evt = slabAllocatorAlloc(mInternalEvents)) != 0) {
100 evt->timerId = tim->id;
101 evt->data = tim->callData;
102 if (!osEnqueuePrivateEvt(EVT_APP_TIMER, evt, timerCallFuncFreeF, tim->tid)) {
103 ERROR_PRINT("Could not enqueue private timer event\n");
104 slabAllocatorFree(mInternalEvents, evt);
105 }
106 } else {
107 ERROR_PRINT("Could not allocate an internal event\n");
108 }
109 }
110 }
111
timFireAsNeededAndUpdateAlarms(void)112 static bool timFireAsNeededAndUpdateAlarms(void)
113 {
114 uint32_t maxDrift = 0, maxJitter = 0, maxErrTotal = 0;
115 bool somethingDone, totalSomethingDone = false;
116 uint64_t nextTimer, expires;
117 uint32_t i;
118 struct Timer *tim;
119
120 // protect from concurrent execution [timIntHandler() and timTimerSetEx()]
121 uint64_t intSta = cpuIntsOff();
122 uint16_t oldTid = osGetCurrentTid();
123
124 do {
125 somethingDone = false;
126 nextTimer = 0;
127
128 for (i = 0, tim = &mTimers[0]; i < MAX_TIMERS; i++, tim++) {
129 if (!tim->id)
130 continue;
131
132 if ((!tim->useRtc && tim->expires <= timGetTime()) || (tim->useRtc && tim->expires <= rtcGetTime())) {
133 somethingDone = true;
134 if (tim->period) {
135 tim->expires += tim->period;
136 timCallFunc(tim);
137 } else {
138 timCallFunc(tim);
139 tim->id = 0;
140 atomicBitsetClearBit(mTimersValid, i);
141 }
142 }
143 else {
144 if (tim->jitterPpm > maxJitter)
145 maxJitter = tim->jitterPpm;
146 if (tim->driftPpm > maxDrift)
147 maxDrift = tim->driftPpm;
148 if (tim->driftPpm + tim->jitterPpm > maxErrTotal)
149 maxErrTotal = tim->driftPpm + tim->jitterPpm;
150 if (tim->useRtc)
151 expires = tim->expires - rtcGetTime() + timGetTime();
152 else
153 expires = tim->expires;
154 if (!nextTimer || nextTimer > expires)
155 nextTimer = expires;
156 }
157 }
158
159 totalSomethingDone = totalSomethingDone || somethingDone;
160
161 //we loop while loop does something, or while (if next timer exists), it is due by the time loop ends, or platform code fails to set an alarm to wake us for it
162 } while (somethingDone || (nextTimer && (timGetTime() >= nextTimer || !platSleepClockRequest(nextTimer, maxJitter, maxDrift, maxErrTotal))));
163
164 if (!nextTimer)
165 platSleepClockRequest(0, 0, 0, 0);
166
167 osSetCurrentTid(oldTid);
168 cpuIntsRestore(intSta);
169
170 return totalSomethingDone;
171 }
172
timTimerSetEx(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,TaggedPtr info,void * data,bool oneShot,bool useRtc)173 static uint32_t timTimerSetEx(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TaggedPtr info, void* data, bool oneShot, bool useRtc)
174 {
175 uint64_t curTime = useRtc ? rtcGetTime() : timGetTime();
176 int32_t idx = atomicBitsetFindClearAndSet(mTimersValid);
177 struct Timer *t;
178 uint16_t timId;
179
180 if (idx < 0) /* no free timers */{
181 ERROR_PRINT("no free timers\n");
182 return 0;
183 }
184
185 /* generate next timer ID */
186 do {
187 timId = atomicAdd32bits(&mNextTimerId, 1) & MAX_TIMER_ID;
188 } while (!timId || timFindTimerById(timId));
189
190 /* grab our struct & fill it in */
191 t = mTimers + idx;
192 t->expires = curTime + length;
193 t->period = oneShot ? 0 : length;
194 t->jitterPpm = jitterPpm;
195 t->driftPpm = driftPpm;
196 t->callInfo = info;
197 t->callData = data;
198 t->useRtc = useRtc;
199 t->tid = osGetCurrentTid();
200
201 /* as soon as we write timer Id, it becomes valid and might fire */
202 t->id = timId;
203
204 /* fire as needed & recalc alarms*/
205 timFireAsNeededAndUpdateAlarms();
206
207 /* woo hoo - done */
208 return timId;
209 }
210
timTimerSet(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,TimTimerCbkF cbk,void * data,bool oneShot)211 uint32_t timTimerSet(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TimTimerCbkF cbk, void* data, bool oneShot)
212 {
213 return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromPtr(cbk), data, oneShot, false);
214 }
215
timTimerSetAsApp(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,uint32_t tid,void * data,bool oneShot)216 uint32_t timTimerSetAsApp(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, uint32_t tid, void* data, bool oneShot)
217 {
218 return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromUint(0), data, oneShot, false);
219 }
220
timTimerSetNew(uint64_t length,const void * data,bool oneShot)221 uint32_t timTimerSetNew(uint64_t length, const void* data, bool oneShot)
222 {
223 return timTimerSetEx(length, 0, 50, taggedPtrMakeFromUint(0), (void *)data, oneShot, true);
224 }
225
timerEventMatch(uint32_t evtType,const void * evtData,void * context)226 static bool timerEventMatch(uint32_t evtType, const void *evtData, void *context)
227 {
228 struct Timer *t = (struct Timer *)context;
229 union SeosInternalSlabData *da = (union SeosInternalSlabData*)evtData;
230 struct TimerEvent *evt;
231
232 if (evtType != EVT_PRIVATE_EVT || !da || da->privateEvt.evtType != EVT_APP_TIMER || !da->privateEvt.evtData)
233 return false;
234
235 evt = (struct TimerEvent *)da->privateEvt.evtData;
236
237 return evt->timerId == t->id;
238 }
239
timTimerCancelEx(uint32_t timerId,bool cancelPending)240 bool timTimerCancelEx(uint32_t timerId, bool cancelPending)
241 {
242 uint64_t intState = cpuIntsOff();
243 struct Timer *t = timFindTimerById(timerId);
244
245 if (t && t->tid == osGetCurrentTid()) {
246 if (cancelPending)
247 osRemovePendingEvents(timerEventMatch, t);
248 t->id = 0; /* this disables it */
249 } else {
250 t = NULL;
251 }
252
253 cpuIntsRestore(intState);
254
255 /* this frees struct */
256 if (t) {
257 atomicBitsetClearBit(mTimersValid, t - mTimers);
258 return true;
259 }
260
261 return false;
262 }
263
timTimerCancel(uint32_t timerId)264 bool timTimerCancel(uint32_t timerId)
265 {
266 return timTimerCancelEx(timerId, false);
267 }
268
timTimerCancelAll(uint32_t tid)269 int timTimerCancelAll(uint32_t tid)
270 {
271 uint64_t intState;
272 struct Timer *tim;
273 int i, count;
274
275 tim = &mTimers[0];
276 intState = cpuIntsOff();
277 for (i = 0, count = 0; i < MAX_TIMERS; ++i, ++tim) {
278 if (tim->tid != tid)
279 continue;
280 count++;
281 osRemovePendingEvents(timerEventMatch, tim);
282 tim->id = 0; /* this disables it */
283 /* this frees struct */
284 atomicBitsetClearBit(mTimersValid, tim - mTimers);
285 }
286 cpuIntsRestore(intState);
287 return count;
288 }
289
timIntHandler(void)290 bool timIntHandler(void)
291 {
292 return timFireAsNeededAndUpdateAlarms();
293 }
294
timInit(void)295 void timInit(void)
296 {
297 atomicBitsetInit(mTimersValid, MAX_TIMERS);
298
299 mInternalEvents = slabAllocatorNew(sizeof(struct TimerEvent), alignof(struct TimerEvent), MAX_INTERNAL_EVENTS);
300 }
301