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/inc/atomicBitset.h>
18 #include <plat/inc/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 #define MAX_INTERNAL_EVENTS 32 //also used for external app timer() calls
31
32 #define INFO_PRINT(fmt, ...) do { \
33 osLog(LOG_INFO, "%s " fmt, "[timer]", ##__VA_ARGS__); \
34 } while (0);
35
36 #define ERROR_PRINT(fmt, ...) INFO_PRINT("%s" fmt, "ERROR: ", ##__VA_ARGS__)
37
38 struct Timer {
39 uint64_t expires; /* time of next expiration */
40 uint64_t period; /* 0 for oneshot */
41 uint16_t id; /* 0 for disabled */
42 uint16_t tid; /* we need TID always, for system management */
43 uint32_t jitterPpm;
44 uint32_t driftPpm;
45 TaggedPtr callInfo;
46 void *callData;
47 };
48
49
50 ATOMIC_BITSET_DECL(mTimersValid, MAX_TIMERS, static);
51 static struct SlabAllocator *mInternalEvents;
52 static struct Timer mTimers[MAX_TIMERS];
53 static volatile uint32_t mNextTimerId = 0;
54
timGetTime(void)55 uint64_t timGetTime(void)
56 {
57 return platGetTicks();
58 }
59
timFindTimerById(uint32_t timId)60 static struct Timer *timFindTimerById(uint32_t timId) /* no locks taken. be careful what you do with this */
61 {
62 uint32_t i;
63
64 for (i = 0; i < MAX_TIMERS; i++)
65 if (mTimers[i].id == timId)
66 return mTimers + i;
67
68 return NULL;
69 }
70
timerCallFuncFreeF(void * event)71 static void timerCallFuncFreeF(void* event)
72 {
73 slabAllocatorFree(mInternalEvents, event);
74 }
75
timCallFunc(struct Timer * tim)76 static void timCallFunc(struct Timer *tim)
77 {
78 struct TimerEvent *evt;
79 TaggedPtr callInfo = tim->callInfo;
80
81 if (taggedPtrIsPtr(callInfo)) {
82 osSetCurrentTid(tim->tid);
83 ((TimTimerCbkF)taggedPtrToPtr(callInfo))(tim->id, tim->callData);
84 } else {
85 osSetCurrentTid(OS_SYSTEM_TID);
86 if ((evt = slabAllocatorAlloc(mInternalEvents)) != 0) {
87 evt->timerId = tim->id;
88 evt->data = tim->callData;
89 if (!osEnqueuePrivateEvt(EVT_APP_TIMER, evt, timerCallFuncFreeF, tim->tid)) {
90 ERROR_PRINT("Could not enqueue private timer event\n");
91 slabAllocatorFree(mInternalEvents, evt);
92 }
93 } else {
94 ERROR_PRINT("Could not allocate an internal event\n");
95 }
96 }
97 }
98
timFireAsNeededAndUpdateAlarms(void)99 static bool timFireAsNeededAndUpdateAlarms(void)
100 {
101 uint32_t maxDrift = 0, maxJitter = 0, maxErrTotal = 0;
102 bool somethingDone, totalSomethingDone = false;
103 uint64_t nextTimer;
104 uint32_t i;
105 struct Timer *tim;
106
107 // protect from concurrent execution [timIntHandler() and timTimerSetEx()]
108 uint64_t intSta = cpuIntsOff();
109 uint16_t oldTid = osGetCurrentTid();
110
111 do {
112 somethingDone = false;
113 nextTimer = 0;
114
115 for (i = 0, tim = &mTimers[0]; i < MAX_TIMERS; i++, tim++) {
116 if (!tim->id)
117 continue;
118
119 if (tim->expires <= timGetTime()) {
120 somethingDone = true;
121 if (tim->period) {
122 tim->expires += tim->period;
123 timCallFunc(tim);
124 } else {
125 timCallFunc(tim);
126 tim->id = 0;
127 atomicBitsetClearBit(mTimersValid, i);
128 }
129 }
130 else {
131 if (tim->jitterPpm > maxJitter)
132 maxJitter = tim->jitterPpm;
133 if (tim->driftPpm > maxDrift)
134 maxDrift = tim->driftPpm;
135 if (tim->driftPpm + tim->jitterPpm > maxErrTotal)
136 maxErrTotal = tim->driftPpm + tim->jitterPpm;
137 if (!nextTimer || nextTimer > tim->expires)
138 nextTimer = tim->expires;
139 }
140 }
141
142 totalSomethingDone = totalSomethingDone || somethingDone;
143
144 //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
145 } while (somethingDone || (nextTimer && (timGetTime() >= nextTimer || !platSleepClockRequest(nextTimer, maxJitter, maxDrift, maxErrTotal))));
146
147 if (!nextTimer)
148 platSleepClockRequest(0, 0, 0, 0);
149
150 osSetCurrentTid(oldTid);
151 cpuIntsRestore(intSta);
152
153 return totalSomethingDone;
154 }
155
timTimerSetEx(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,TaggedPtr info,void * data,bool oneShot)156 static uint32_t timTimerSetEx(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TaggedPtr info, void* data, bool oneShot)
157 {
158 uint64_t curTime = timGetTime();
159 int32_t idx = atomicBitsetFindClearAndSet(mTimersValid);
160 struct Timer *t;
161 uint16_t timId;
162
163 if (idx < 0) /* no free timers */{
164 ERROR_PRINT("no free timers\n");
165 return 0;
166 }
167
168 /* generate next timer ID */
169 do {
170 timId = atomicAdd32bits(&mNextTimerId, 1);
171 } while (!timId || timFindTimerById(timId));
172
173 /* grab our struct & fill it in */
174 t = mTimers + idx;
175 t->expires = curTime + length;
176 t->period = oneShot ? 0 : length;
177 t->jitterPpm = jitterPpm;
178 t->driftPpm = driftPpm;
179 t->callInfo = info;
180 t->callData = data;
181
182 /* as soon as we write timer Id, it becomes valid and might fire */
183 t->id = timId;
184 t->tid = osGetCurrentTid();
185
186 /* fire as needed & recalc alarms*/
187 timFireAsNeededAndUpdateAlarms();
188
189 /* woo hoo - done */
190 return timId;
191 }
192
timTimerSet(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,TimTimerCbkF cbk,void * data,bool oneShot)193 uint32_t timTimerSet(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, TimTimerCbkF cbk, void* data, bool oneShot)
194 {
195 return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromPtr(cbk), data, oneShot);
196 }
197
timTimerSetAsApp(uint64_t length,uint32_t jitterPpm,uint32_t driftPpm,uint32_t tid,void * data,bool oneShot)198 uint32_t timTimerSetAsApp(uint64_t length, uint32_t jitterPpm, uint32_t driftPpm, uint32_t tid, void* data, bool oneShot)
199 {
200 return timTimerSetEx(length, jitterPpm, driftPpm, taggedPtrMakeFromUint(0), data, oneShot);
201 }
202
timTimerCancel(uint32_t timerId)203 bool timTimerCancel(uint32_t timerId)
204 {
205 uint64_t intState = cpuIntsOff();
206 struct Timer *t = timFindTimerById(timerId);
207
208 if (t)
209 t->id = 0; /* this disables it */
210
211 cpuIntsRestore(intState);
212
213 /* this frees struct */
214 if (t) {
215 atomicBitsetClearBit(mTimersValid, t - mTimers);
216 return true;
217 }
218
219 return false;
220 }
221
timTimerCancelAll(uint32_t tid)222 int timTimerCancelAll(uint32_t tid)
223 {
224 uint64_t intState;
225 struct Timer *tim;
226 int i, count;
227
228 tim = &mTimers[0];
229 intState = cpuIntsOff();
230 for (i = 0, count = 0; i < MAX_TIMERS; ++i, ++tim) {
231 if (tim->tid != tid)
232 continue;
233 count++;
234 tim->id = 0; /* this disables it */
235 /* this frees struct */
236 atomicBitsetClearBit(mTimersValid, tim - mTimers);
237 }
238 cpuIntsRestore(intState);
239 return count;
240 }
241
timIntHandler(void)242 bool timIntHandler(void)
243 {
244 return timFireAsNeededAndUpdateAlarms();
245 }
246
timInit(void)247 void timInit(void)
248 {
249 atomicBitsetInit(mTimersValid, MAX_TIMERS);
250
251 mInternalEvents = slabAllocatorNew(sizeof(struct TimerEvent), alignof(struct TimerEvent), MAX_INTERNAL_EVENTS);
252 }
253