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 55 uint64_t timGetTime(void) 56 { 57 return platGetTicks(); 58 } 59 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 71 static void timerCallFuncFreeF(void* event) 72 { 73 slabAllocatorFree(mInternalEvents, event); 74 } 75 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 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 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 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 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 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 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 242 bool timIntHandler(void) 243 { 244 return timFireAsNeededAndUpdateAlarms(); 245 } 246 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