1/* 2 * Copyright 2017, 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(DATA61_BSD) 11 */ 12 13#include <autoconf.h> 14 15#include <assert.h> 16#include <stdio.h> 17#include <stdbool.h> 18#include <stdio.h> 19#include <errno.h> 20#include <sel4/sel4.h> 21#include <sel4/arch/constants.h> 22#include <camkes.h> 23#include <camkes/irq.h> 24#include <platsupport/time_manager.h> 25#include <platsupport/local_time_manager.h> 26#include <platsupport/irq.h> 27#include <utils/util.h> 28#include <sel4utils/sel4_zf_logif.h> 29#include <simple/simple.h> 30#include <camkes/io.h> 31 32#include "plat.h" 33 34/* ltimer for accessing timer devices */ 35static ltimer_t ltimer; 36/* time manager for timeout multiplexing */ 37static time_manager_t time_manager; 38 39/* declare the memory needed for the clients 40 * this field tracks which timeouts have triggered 41 * for a specific client */ 42uint32_t *client_state = NULL; 43 44/* Prototype for this function is not generated by the camkes templates yet */ 45seL4_Word the_timer_get_sender_id(); 46void the_timer_emit(unsigned int); 47int the_timer_largest_badge(void); 48 49static ps_io_ops_t io_ops; 50 51static inline uint64_t current_time_ns() 52{ 53 uint64_t time; 54 int error = ltimer_get_time(<imer, &time); 55 ZF_LOGF_IF(error, "Failed to get time"); 56 return time; 57} 58 59static inline unsigned int get_time_token(int cid, int tid) 60{ 61 return (unsigned int) cid * timers_per_client + tid; 62} 63 64static int signal_client(uintptr_t token) 65{ 66 67 int cid = ((int) token) / timers_per_client; 68 int tid = ((int) token) % timers_per_client; 69 70 assert(client_state != NULL); 71 72 client_state[cid] |= BIT(tid); 73 the_timer_emit(cid + 1); 74 75 return 0; 76} 77 78void time_server_ltimer_handle(UNUSED void *empty_token, ltimer_event_t ltimer_event) 79{ 80 int error = time_server_lock(); 81 ZF_LOGF_IF(error, "Failed to lock time server"); 82 83 error = tm_update(&time_manager); 84 ZF_LOGF_IF(error, "Failed to update time manager"); 85 86 error = time_server_unlock(); 87 ZF_LOGF_IF(error, "Failed to unlock time server"); 88} 89 90static int _oneshot_relative(int cid, int tid, uint64_t ns) 91{ 92 if (tid >= timers_per_client || tid < 0) { 93 ZF_LOGE("invalid tid, 0 >= %d >= %d\n", tid, timers_per_client); 94 return -1; 95 } 96 97 int error = time_server_lock(); 98 ZF_LOGF_IF(error, "Failed to lock time server"); 99 100 unsigned int id = get_time_token(cid, tid); 101 error = tm_register_rel_cb(&time_manager, ns, id, signal_client, (uintptr_t) id); 102 ZF_LOGF_IF(error, "Failed to set timeout"); 103 104 error = time_server_unlock(); 105 ZF_LOGF_IF(error, "Failed to unlock time server"); 106 return 0; 107} 108 109static int _oneshot_absolute(int cid, int tid, uint64_t ns) 110{ 111 if (tid >= timers_per_client || tid < 0) { 112 ZF_LOGE("invalid tid, 0 >= %d >= %d\n", tid, timers_per_client); 113 return -1; 114 } 115 116 int error = time_server_lock(); 117 ZF_LOGF_IF(error, "Failed to lock time server"); 118 119 unsigned int token = get_time_token(cid, tid); 120 121 error = tm_register_abs_cb(&time_manager, ns, token, signal_client, (uintptr_t) token); 122 if (error == ETIME) { 123 signal_client(token); 124 error = 0; 125 } 126 ZF_LOGF_IF(error, "Failed to set timeout"); 127 128 error = time_server_unlock(); 129 ZF_LOGF_IF(error, "Failed to unlock time server"); 130 return 0; 131} 132 133static int _periodic(int cid, int tid, uint64_t ns) 134{ 135 if (tid >= timers_per_client || tid < 0) { 136 ZF_LOGE("invalid tid, 0 >= %d >= %d\n", tid, timers_per_client); 137 return -1; 138 } 139 140 int error = time_server_lock(); 141 ZF_LOGF_IF(error, "Failed to lock time server"); 142 143 unsigned int token = get_time_token(cid, tid); 144 error = tm_register_periodic_cb(&time_manager, ns, 0, token, signal_client, (uintptr_t) token); 145 ZF_LOGF_IF(error, "Failed to set timeout"); 146 147 error = time_server_unlock(); 148 ZF_LOGF_IF(error, "Failed to unlock time server"); 149 return 0; 150} 151 152static int _stop(int cid, int tid) 153{ 154 if (tid >= timers_per_client || tid < 0) { 155 ZF_LOGE("invalid tid, 0 >= %d >= %d\n", tid, timers_per_client); 156 return -1; 157 } 158 int error = time_server_lock(); 159 ZF_LOGF_IF(error, "Failed to lock time server"); 160 161 error = tm_deregister_cb(&time_manager, get_time_token(cid, tid)); 162 ZF_LOGF_IF(error, "Failed to deregister callback"); 163 164 error = time_server_unlock(); 165 ZF_LOGF_IF(error, "Failed to unlock time server"); 166 return 0; 167} 168 169static unsigned int _completed(int cid) 170{ 171 int error = time_server_lock(); 172 ZF_LOGF_IF(error, "Failed to lock time server"); 173 174 assert(client_state != NULL); 175 unsigned int ret = client_state[cid]; 176 client_state[cid] = 0; 177 178 error = time_server_unlock(); 179 ZF_LOGF_IF(error, "Failed to unlock time server"); 180 181 return ret; 182} 183 184static uint64_t _time(int cid) 185{ 186 return current_time_ns(); 187} 188 189/* substract 1 from the badge as we started counting badges at 1 190 * to avoid using the 0 badge */ 191int the_timer_oneshot_relative(int id, uint64_t ns) 192{ 193 return _oneshot_relative(the_timer_get_sender_id() - 1, id, ns); 194} 195 196int the_timer_oneshot_absolute(int id, uint64_t ns) 197{ 198 return _oneshot_absolute(the_timer_get_sender_id() - 1, id, ns); 199} 200 201int the_timer_periodic(int id, uint64_t ns) 202{ 203 return _periodic(the_timer_get_sender_id() - 1, id, ns); 204} 205 206int the_timer_stop(int id) 207{ 208 return _stop(the_timer_get_sender_id() - 1, id); 209} 210 211unsigned int the_timer_completed() 212{ 213 return _completed(the_timer_get_sender_id() - 1); 214} 215 216uint64_t the_timer_time() 217{ 218 return _time(the_timer_get_sender_id() - 1); 219} 220 221void post_init() 222{ 223 int error = time_server_lock(); 224 ZF_LOGF_IF(error, "Failed to lock timer server"); 225 226 error = camkes_io_ops(&io_ops); 227 ZF_LOGF_IF(error, "Failed to get camkes_io_ops"); 228 229 error = ps_calloc(&(io_ops.malloc_ops), the_timer_largest_badge(), sizeof(*client_state), (void **) &client_state); 230 ZF_LOGF_IF(error, "Failed to allocate client state"); 231 232 if (plat_pre_init) { 233 plat_pre_init(); 234 } 235 236 error = ltimer_default_init(<imer, io_ops, time_server_ltimer_handle, NULL); 237 ZF_LOGF_IF(error, "Failed to init timer"); 238 239 if (plat_post_init) { 240 plat_post_init(<imer); 241 } 242 243 int num_timers = timers_per_client * the_timer_largest_badge(); 244 tm_init(&time_manager, <imer, &io_ops, num_timers); 245 for (unsigned int i = 0; i < num_timers; i++) { 246 error = tm_alloc_id_at(&time_manager, i); 247 ZF_LOGF_IF(error, "Failed to alloc id at %u\n", i); 248 } 249 250 error = time_server_unlock(); 251 ZF_LOGF_IF(error, "Failed to unlock timer server"); 252 253 set_putchar(putchar_putchar); 254} 255