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