1/* 2 * Copyright 2016, Data61 3 * Commonwealth Scientific and Industrial Research Organisation (CSIRO) 4 * ABN 41 687 119 230. 5 * 6 * This software may be distributed and modified according to the terms of 7 * the BSD 2-Clause license. Note that NO WARRANTY is provided. 8 * See "LICENSE_BSD2.txt" for details. 9 * 10 * @TAG(D61_BSD) 11 */ 12 13#include <stdio.h> 14#include <stdlib.h> 15#include <stdint.h> 16#include <stdbool.h> 17#include <autoconf.h> 18#include <assert.h> 19#include <time.h> 20 21#include "device_timer.h" 22#include "state.h" 23#include <platsupport/timer.h> 24#include <platsupport/plat/timer.h> 25#include <refos-util/dprintf.h> 26#include <refos-util/device_io.h> 27 28/*! @file 29 @brief timer server timer device manager. 30 31 This module is responsible for managing the timer state. IT is a thin wrapper on top of the 32 timer device drivers provided by libplatsupport. 33 34 When a client wants to sleep for some amount of seconds, we use seL4_CNode_SaveCaller in order 35 to save its reply cap and reply to it when on the timer IRQ when its sleep period has expired. 36 The timer module sets up frequent periodic timer IRQs in order to do this. 37 38 This approach is relatively inefficient as it results in a lot of IRQs and wasted time 39 processing them. A better approach would be to set up one-shot IRQs at the exact time of the 40 next waking client, allowing less IRQ overhead and much better sleep accuracy. This may be 41 implemented in the near future, but for now spamming IRQs is a simple approach which works. 42*/ 43 44/* ---------------------- Platform specific timer device definitions ---------------------------- */ 45 46#if defined(PLAT_IMX31) || defined (PLAT_IMX6) 47 48 #define TIMER_PADDR GPT1_DEVICE_PADDR 49 #define TIMER_PERIODIC_MAX_SET false /* We don't explicitly set period for GPT. */ 50 #define TIMER_PERIODIC_MAX (((1ULL << 32) / 66UL) * 1000UL) 51 52 #define TICK_TIMER_PADDR EPIT2_DEVICE_PADDR 53 #define TICK_TIMER_IRQ EPIT2_INTERRUPT 54 #define TICK_TIMER_PERIOD (2000000) 55 #define TICK_TIMER_SCALE_NS 1 56 57#elif defined(PLAT_AM335x) 58 59 #define TIMER_ID DMTIMER2 60 #define TICK_ID DMTIMER3 61 #define TIMER_PERIODIC_MAX_SET true 62 /* XXX am I doing this right? this is the largest period in nsec you can pass to the timer APIs */ 63 #define TIMER_PERIODIC_MAX 178956970666 // ((((1UL << 32) / 24UL) * 1000UL) - 1) 64 #define TICK_TIMER_PERIOD (2000000) 65 #define TICK_TIMER_SCALE_NS 1 66 67#elif defined(PLAT_PC99) 68 69 /* PIT only needs IOPort operations. */ 70 #define TIMER_PERIODIC_MAX_SET true 71 #define TIMER_PERIODIC_MAX 54925000 72 73 #define TICK_TIMER_PERIOD (2000000) 74 #define TICK_TIMER_SCALE_NS 1 75 76 #include <platsupport/plat/rtc.h> 77 78#else 79 #error "Unsupported platform." 80#endif 81 82/* ------------------------------------ Timer functions ----------------------------------------- */ 83 84/* Forward declarations. We avoid including the whole state.h here due to errno.h definition 85 conflicts. */ 86typedef void (*timeserv_irq_callback_fn_t)(void *cookie, uint32_t irq); 87int timeserv_handle_irq(uint32_t irq, timeserv_irq_callback_fn_t callback, void *cookie); 88void reply_data_write(void *rpc_userptr, int rpc___ret__); 89 90/*! @brief Look at sleeper list and reply to any sleppers that have had their time requirements 91 met. 92 @param s The timer global state structure. 93*/ 94static void 95device_timer_update_sleepers(struct device_timer_state *s) 96{ 97 uint64_t time = device_timer_get_time(s); 98 99 /* Loop through and find any fired waiters to reply to. */ 100 int count = cvector_count(&s->waiterList); 101 for (int i = 0; i < count; i++) { 102 struct device_timer_waiter *waiter = (struct device_timer_waiter*) 103 cvector_get(&s->waiterList, i); 104 assert(waiter && waiter->magic == TIMESERV_DEVICE_TIMER_WAITER_MAGIC); 105 assert(waiter->reply && waiter->client); 106 107 if (waiter->time > time) { 108 /* Not yet. */ 109 continue; 110 } 111 112 /* Reply to the waiter. */ 113 waiter->client->rpcClient.skip_reply = false; 114 waiter->client->rpcClient.reply = waiter->reply; 115 reply_data_write((void*) waiter->client, sizeof(uint64_t)); 116 117 /* Delete the saved reply cap, and free the structure. */ 118 waiter->client->rpcClient.reply = 0; 119 csfree_delete(waiter->reply); 120 waiter->magic = 0x0; 121 free(waiter); 122 123 /* Remove the item from the waiter list. */ 124 cvector_delete(&s->waiterList, i); 125 count = cvector_count(&s->waiterList); 126 i--; 127 } 128} 129 130/*! @brief Callback function to handle GPT timer IRQs. 131 132 GPT timer IRQs happen on GPT timer overflow. Note that the GPT device (used to get the actual 133 time) may actually be the excat same device as the waiting-list IRQ generator device, depending 134 on the platform. 135 136 @param cookie The global timer state (struct device_timer_state *). 137 @param irq The fired IRQ number. 138*/ 139static void 140device_timer_handle_irq(void *cookie, uint32_t irq) 141{ 142 struct device_timer_state *s = (struct device_timer_state *) cookie; 143 assert(s && s->magic == TIMESERV_DEVICE_TIMER_MAGIC); 144 assert(s->timerIRQPeriod > 0); 145 s->cumulativeTime += s->timerIRQPeriod; 146 timer_handle_irq(s->timerDev, irq); 147 device_timer_update_sleepers(s); 148} 149 150/*! @brief Callback function to handle waiter timer IRQs. 151 152 Waiter-list IRQs happen very frequently, as opposed to the GPT overflow IRQs. This is used to 153 wake up sleeping clients. 154 155 @param cookie The global timer state (struct device_timer_state *). 156 @param irq The fired IRQ number. 157*/ 158static void 159device_tick_handle_irq(void *cookie, uint32_t irq) 160{ 161 struct device_timer_state *s = (struct device_timer_state *) cookie; 162 assert(s && s->magic == TIMESERV_DEVICE_TIMER_MAGIC); 163 timer_handle_irq(s->tickDev, irq); 164 device_timer_update_sleepers(s); 165} 166 167static void 168device_timer_init_rtc(struct device_timer_state *s, dev_io_ops_t *io) 169{ 170 assert(s && io); 171 s->cumulativeTime = 0; 172 173 #if defined(PLAT_PC99) 174 175 rtc_time_date_t rtcTimeDate; 176 int error = rtc_get_time_date_reg(&io->opsIO.io_port_ops, 0, &rtcTimeDate); 177 if (error) { 178 ROS_ERROR("Could not read RTC."); 179 return; 180 } 181 182 struct tm timeInfo = {0}; 183 timeInfo.tm_sec = rtcTimeDate.second; 184 timeInfo.tm_min = rtcTimeDate.minute; 185 timeInfo.tm_hour = rtcTimeDate.hour; 186 timeInfo.tm_mday = rtcTimeDate.day; 187 timeInfo.tm_mon = rtcTimeDate.month - 1; 188 timeInfo.tm_year = rtcTimeDate.year - 1900; 189 190 time_t epochSeconds = mktime(&timeInfo); 191 s->cumulativeTime = (uint64_t) epochSeconds * 1000000000ULL; 192 193 #endif 194} 195 196void 197device_timer_init(struct device_timer_state *s, dev_io_ops_t *io) 198{ 199 assert(s && io); 200 assert(!s->initialised); 201 202 s->magic = TIMESERV_DEVICE_TIMER_MAGIC; 203 s->io = io; 204 s->timerDev = NULL; 205 206#if defined(PLAT_IMX31) || defined (PLAT_IMX6) 207 208 /* Map the GPT (General Purpose Timer) device to use as the clock. */ 209 gpt_config_t config; 210 config.vaddr = ps_io_map(&io->opsIO.io_mapper, TIMER_PADDR, 0x1000, 211 false, PS_MEM_NORMAL); 212 config.prescaler = 0; 213 if (!config.vaddr) { 214 ROS_ERROR("Could not map timer device."); 215 assert(!"Could not map timer device."); 216 return; 217 } 218 219 /* Get timer interface from given GPT device. */ 220 s->timerDev = gpt_get_timer(&config); 221 222 /* Map the EPIT device to use as the tick source. */ 223 epit_config_t econfig; 224 econfig.vaddr = ps_io_map(&io->opsIO.io_mapper, TICK_TIMER_PADDR, 0x1000, 225 false, PS_MEM_NORMAL); 226 econfig.prescaler = 0; 227 econfig.irq = TICK_TIMER_IRQ; 228 if (!econfig.vaddr) { 229 ROS_ERROR("Could not map tick timer device."); 230 assert(!"Could not map tick timer device."); 231 return; 232 } 233 234 /* Get the timer interface from EPIT device. */ 235 s->tickDev = epit_get_timer(&econfig); 236 237#elif defined(PLAT_AM335x) 238 239 timer_config_t config; 240 config.vaddr = ps_io_map(&io->opsIO.io_mapper, dm_timer_paddrs[TIMER_ID], 241 0x1000, false, PS_MEM_NORMAL); 242 config.irq = dm_timer_irqs[TIMER_ID]; 243 if (!config.vaddr) { 244 ROS_ERROR("Could not map timer device."); 245 assert(!"Could not map timer device."); 246 return; 247 } 248 s->timerDev = ps_get_timer(TIMER_ID, &config); 249 250 config.vaddr = ps_io_map(&io->opsIO.io_mapper, dm_timer_paddrs[TICK_ID], 251 0x1000, false, PS_MEM_NORMAL); 252 config.irq = dm_timer_irqs[TICK_ID]; 253 if (!config.vaddr) { 254 ROS_ERROR("Could not map tick timer device."); 255 assert(!"Could not map tick timer device."); 256 return; 257 } 258 s->tickDev = ps_get_timer(TICK_ID, &config); 259 260#elif defined(PLAT_PC99) 261 262 s->timerDev = pit_get_timer(&io->opsIO.io_port_ops); 263 s->tickDev = s->timerDev; 264 265#endif 266 267 if (!s->timerDev) { 268 ROS_ERROR("Could not initialise timer."); 269 return; 270 } 271 272 /* Set up to recieve timer IRQs. */ 273 for (uint32_t i = 0; i < s->timerDev->properties.irqs; i++) { 274 int irq = timer_get_nth_irq(s->timerDev, i); 275 int error = dev_handle_irq(&timeServ.irqState, irq, device_timer_handle_irq, (void*) s); 276 assert(!error); 277 (void) error; 278 } 279 280 /* Set up to recieve tick timer IRQs. */ 281 if (s->tickDev != NULL && s->tickDev != s->timerDev) { 282 for (uint32_t i = 0; i < s->tickDev->properties.irqs; i++) { 283 int irq = timer_get_nth_irq(s->tickDev, i); 284 int error = dev_handle_irq(&timeServ.irqState, irq, device_tick_handle_irq, (void*) s); 285 assert(!error); 286 (void) error; 287 } 288 289 int error = timer_start(s->tickDev); 290 if (error) { 291 ROS_ERROR("Could not start tick timer."); 292 assert(!"Tick timer initialise but could not start."); 293 return; 294 } 295 } 296 297 /* Read the RTC. */ 298 device_timer_init_rtc(s, io); 299 300 /* Start the timer. */ 301 int error = timer_start(s->timerDev); 302 if (error) { 303 ROS_ERROR("Could not start timer."); 304 assert(!"Timer initialise but could not start."); 305 return; 306 } 307 308 #if TIMER_PERIODIC_MAX_SET 309 /* Set the timer for periodic overflow interrupts. */ 310 error = timer_periodic(s->timerDev, TIMER_PERIODIC_MAX); 311 if (error) { 312 ROS_ERROR("Could not configure periodic timer."); 313 assert(!"Could not set periodic timer."); 314 return; 315 } 316 #endif 317 s->timerIRQPeriod = TIMER_PERIODIC_MAX; 318 319 /* Set the tick timer for realy fast periodic ticks. Rather crude way of implementing sleep() 320 functionality but works. In the future this should be improved 321 (see module description above). 322 */ 323 if (s->tickDev != NULL) { 324 error = timer_periodic(s->tickDev, TICK_TIMER_PERIOD); 325 if (error) { 326 ROS_WARNING("Could not set periodic tick timer."); 327 assert(!"Could not set periodic tick timer."); 328 } 329 if (s->tickDev == s->timerDev) { 330 s->timerIRQPeriod = TICK_TIMER_PERIOD; 331 } 332 } 333 334 /* Initialise the sleep timer waiter list. */ 335 cvector_init(&s->waiterList); 336 337 s->initialised = true; 338} 339 340uint64_t 341device_timer_get_time(struct device_timer_state *s) 342{ 343 assert(s && s->magic == TIMESERV_DEVICE_TIMER_MAGIC); 344 uint64_t time = timer_get_time(s->timerDev); 345 if (!s->timerDev->properties.upcounter) { 346 /* This is a downcounter timer. Invert the time. */ 347 assert(time <= s->timerIRQPeriod); 348 time = s->timerIRQPeriod - time; 349 } 350 time += s->cumulativeTime; 351 return time * TICK_TIMER_SCALE_NS; 352} 353 354int 355device_timer_save_caller_as_waiter(struct device_timer_state *s, struct srv_client *c, 356 uint64_t waitTime) 357{ 358 assert(s && s->magic == TIMESERV_DEVICE_TIMER_MAGIC); 359 assert(c && c->magic == TIMESERV_CLIENT_MAGIC); 360 int error = EINVALID; 361 362 /* Allocate and fill out waiter structure. */ 363 struct device_timer_waiter *waiter = malloc(sizeof(struct device_timer_waiter)); 364 if (!waiter) { 365 ROS_ERROR("device_timer_save_caller_as_waiter failed to alloc waiter struct."); 366 return ENOMEM; 367 } 368 waiter->magic = TIMESERV_DEVICE_TIMER_WAITER_MAGIC; 369 waiter->client = c; 370 waiter->time = (waitTime / TICK_TIMER_SCALE_NS) + device_timer_get_time(s); 371 372 /* Allocate a cslot to save the reply cap into. */ 373 waiter->reply = csalloc(); 374 if (!waiter->reply) { 375 ROS_ERROR("device_timer_save_caller_as_waiter failed to alloc cslot."); 376 error = ENOMEM; 377 goto exit1; 378 } 379 380 /* Save current caller into the reply cap. */ 381 error = seL4_CNode_SaveCaller(REFOS_CSPACE, waiter->reply, REFOS_CDEPTH); 382 if (error != seL4_NoError) { 383 ROS_ERROR("device_timer_save_caller_as_waiter failed to save caller."); 384 error = EINVALID; 385 goto exit2; 386 } 387 388 /* Add to waiter list. (Takes ownership) */ 389 cvector_add(&s->waiterList, (cvector_item_t) waiter); 390 391 return ESUCCESS; 392 393 /* Exit stack. */ 394exit2: 395 csfree(waiter->reply); 396exit1: 397 waiter->magic = 0; 398 free(waiter); 399 return error; 400} 401 402void 403device_timer_purge_client(struct device_timer_state *client) 404{ 405 assert(!"not implemented."); 406} 407