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